]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzi...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Jun 2009 18:23:17 +0000 (11:23 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Jun 2009 18:23:17 +0000 (11:23 -0700)
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev:
  [libata] ata_piix: Enable parallel scan
  sata_nv: use hardreset only for post-boot probing
  [libata] ahci: Restore SB600 SATA controller 64 bit DMA
  ata_piix: Remove stale comment
  ata_piix: Turn on hotplugging support for older chips
  ahci: misc cleanups for EM stuff
  [libata] get rid of ATA_MAX_QUEUE loop in ata_qc_complete_multiple() v2
  sata_sil: enable 32-bit PIO
  sata_sx4: speed up ECC initialization
  libata-sff: avoid byte swapping in ata_sff_data_xfer()
  [libata] ahci: use less error-prone array initializers

1113 files changed:
Documentation/ABI/testing/sysfs-block
Documentation/ABI/testing/sysfs-bus-pci-devices-cciss [new file with mode: 0644]
Documentation/ABI/testing/sysfs-devices-cache_disable [new file with mode: 0644]
Documentation/DMA-API.txt
Documentation/DocBook/Makefile
Documentation/DocBook/tracepoint.tmpl [new file with mode: 0644]
Documentation/RCU/trace.txt
Documentation/Smack.txt
Documentation/block/biodoc.txt
Documentation/filesystems/gfs2-glocks.txt
Documentation/filesystems/gfs2.txt
Documentation/futex-requeue-pi.txt [new file with mode: 0644]
Documentation/kernel-parameters.txt
Documentation/memory-barriers.txt
Documentation/scheduler/sched-rt-group.txt
Documentation/sysctl/kernel.txt
Documentation/trace/events.txt [new file with mode: 0644]
Documentation/trace/ftrace.txt
Documentation/trace/power.txt [new file with mode: 0644]
Documentation/x86/boot.txt
Documentation/x86/x86_64/boot-options.txt
Documentation/x86/x86_64/mm.txt
MAINTAINERS
arch/alpha/kernel/sys_dp264.c
arch/alpha/kernel/sys_titan.c
arch/arm/common/gic.c
arch/arm/plat-mxc/include/mach/imx-uart.h
arch/arm/plat-omap/mailbox.c
arch/cris/arch-v32/kernel/irq.c
arch/frv/Kconfig
arch/frv/include/asm/bitops.h
arch/frv/include/asm/elf.h
arch/frv/include/asm/pci.h
arch/frv/include/asm/ptrace.h
arch/frv/include/asm/syscall.h [new file with mode: 0644]
arch/frv/include/asm/thread_info.h
arch/frv/kernel/entry.S
arch/frv/kernel/ptrace.c
arch/frv/kernel/signal.c
arch/frv/kernel/uaccess.c
arch/frv/mb93090-mb00/pci-dma-nommu.c
arch/frv/mb93090-mb00/pci-dma.c
arch/ia64/hp/sim/hpsim_irq.c
arch/ia64/include/asm/kvm_host.h
arch/ia64/include/asm/pgtable.h
arch/ia64/kernel/acpi.c
arch/ia64/kernel/iosapic.c
arch/ia64/kernel/irq_ia64.c
arch/ia64/kernel/msi_ia64.c
arch/ia64/kvm/Kconfig
arch/ia64/kvm/kvm-ia64.c
arch/ia64/kvm/kvm_fw.c
arch/ia64/kvm/lapic.h
arch/ia64/kvm/optvfault.S
arch/ia64/kvm/process.c
arch/ia64/kvm/vcpu.c
arch/ia64/kvm/vmm.c
arch/ia64/kvm/vmm_ivt.S
arch/ia64/kvm/vtlb.c
arch/ia64/sn/kernel/irq.c
arch/ia64/sn/kernel/msi_sn.c
arch/mips/cavium-octeon/octeon-irq.c
arch/mips/include/asm/irq.h
arch/mips/kernel/irq-gic.c
arch/mips/mti-malta/malta-smtc.c
arch/mips/sibyte/bcm1480/irq.c
arch/mips/sibyte/sb1250/irq.c
arch/mn10300/Kconfig
arch/mn10300/include/asm/elf.h
arch/mn10300/include/asm/processor.h
arch/mn10300/include/asm/ptrace.h
arch/mn10300/kernel/entry.S
arch/mn10300/kernel/ptrace.c
arch/mn10300/kernel/signal.c
arch/mn10300/mm/tlb-mn10300.S
arch/parisc/kernel/irq.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/platforms/pseries/xics.c
arch/powerpc/sysdev/axonram.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/mpic.h
arch/s390/include/asm/kvm_host.h
arch/s390/kvm/intercept.c
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/priv.c
arch/s390/kvm/sigp.c
arch/sh/Kconfig
arch/sh/Kconfig.cpu
arch/sh/Kconfig.debug
arch/sh/Makefile
arch/sh/boards/Kconfig
arch/sh/boards/board-ap325rxa.c
arch/sh/boards/board-sh7785lcr.c
arch/sh/boards/mach-cayman/Makefile
arch/sh/boards/mach-cayman/irq.c
arch/sh/boards/mach-cayman/panic.c [new file with mode: 0644]
arch/sh/boards/mach-cayman/setup.c
arch/sh/boards/mach-dreamcast/setup.c
arch/sh/boards/mach-migor/setup.c
arch/sh/boards/mach-r2d/setup.c
arch/sh/boards/mach-se/7724/Makefile [new file with mode: 0644]
arch/sh/boards/mach-se/7724/irq.c [new file with mode: 0644]
arch/sh/boards/mach-se/7724/setup.c [new file with mode: 0644]
arch/sh/boards/mach-se/7751/Makefile
arch/sh/boards/mach-se/7751/io.c
arch/sh/boards/mach-se/7751/pci.c [deleted file]
arch/sh/boards/mach-se/7780/irq.c
arch/sh/boards/mach-se/Makefile
arch/sh/boards/mach-sh03/rtc.c
arch/sh/boards/mach-snapgear/io.c
arch/sh/boards/mach-systemh/io.c
arch/sh/boards/mach-titan/io.c
arch/sh/boot/Makefile
arch/sh/boot/compressed/Makefile
arch/sh/boot/compressed/Makefile_32 [deleted file]
arch/sh/boot/compressed/Makefile_64 [deleted file]
arch/sh/boot/compressed/head_64.S
arch/sh/boot/compressed/vmlinux_64.lds [deleted file]
arch/sh/cchips/Kconfig
arch/sh/cchips/hd6446x/hd64461.c
arch/sh/configs/ap325rxa_defconfig
arch/sh/configs/cayman_defconfig
arch/sh/configs/dreamcast_defconfig
arch/sh/configs/edosk7705_defconfig
arch/sh/configs/edosk7760_defconfig
arch/sh/configs/espt_defconfig
arch/sh/configs/hp6xx_defconfig
arch/sh/configs/landisk_defconfig
arch/sh/configs/lboxre2_defconfig
arch/sh/configs/magicpanelr2_defconfig
arch/sh/configs/microdev_defconfig
arch/sh/configs/migor_defconfig
arch/sh/configs/polaris_defconfig
arch/sh/configs/r7780mp_defconfig
arch/sh/configs/r7785rp_defconfig
arch/sh/configs/rsk7201_defconfig
arch/sh/configs/rsk7203_defconfig
arch/sh/configs/rts7751r2d1_defconfig
arch/sh/configs/rts7751r2dplus_defconfig
arch/sh/configs/sdk7780_defconfig
arch/sh/configs/se7206_defconfig
arch/sh/configs/se7343_defconfig
arch/sh/configs/se7619_defconfig
arch/sh/configs/se7705_defconfig
arch/sh/configs/se7712_defconfig
arch/sh/configs/se7721_defconfig
arch/sh/configs/se7722_defconfig
arch/sh/configs/se7724_defconfig [new file with mode: 0644]
arch/sh/configs/se7750_defconfig
arch/sh/configs/se7751_defconfig
arch/sh/configs/se7780_defconfig
arch/sh/configs/sh03_defconfig
arch/sh/configs/sh7710voipgw_defconfig
arch/sh/configs/sh7724_generic_defconfig [new file with mode: 0644]
arch/sh/configs/sh7763rdp_defconfig
arch/sh/configs/sh7770_generic_defconfig [new file with mode: 0644]
arch/sh/configs/sh7785lcr_32bit_defconfig
arch/sh/configs/sh7785lcr_defconfig
arch/sh/configs/shmin_defconfig
arch/sh/configs/shx3_defconfig
arch/sh/configs/snapgear_defconfig
arch/sh/configs/systemh_defconfig
arch/sh/configs/titan_defconfig
arch/sh/configs/ul2_defconfig
arch/sh/configs/urquell_defconfig
arch/sh/drivers/dma/Kconfig
arch/sh/drivers/pci/Kconfig
arch/sh/drivers/pci/Makefile
arch/sh/drivers/pci/fixups-cayman.c [moved from arch/sh/drivers/pci/ops-cayman.c with 88% similarity]
arch/sh/drivers/pci/fixups-dreamcast.c
arch/sh/drivers/pci/fixups-landisk.c [moved from arch/sh/drivers/pci/ops-landisk.c with 51% similarity]
arch/sh/drivers/pci/fixups-lboxre2.c [deleted file]
arch/sh/drivers/pci/fixups-r7780rp.c
arch/sh/drivers/pci/fixups-rts7751r2d.c
arch/sh/drivers/pci/fixups-sdk7780.c
arch/sh/drivers/pci/fixups-se7751.c [new file with mode: 0644]
arch/sh/drivers/pci/fixups-se7780.c [deleted file]
arch/sh/drivers/pci/fixups-sh7785lcr.c [deleted file]
arch/sh/drivers/pci/fixups-snapgear.c [new file with mode: 0644]
arch/sh/drivers/pci/fixups-titan.c [moved from arch/sh/drivers/pci/ops-titan.c with 50% similarity]
arch/sh/drivers/pci/ops-dreamcast.c
arch/sh/drivers/pci/ops-lboxre2.c [deleted file]
arch/sh/drivers/pci/ops-r7780rp.c [deleted file]
arch/sh/drivers/pci/ops-rts7751r2d.c [deleted file]
arch/sh/drivers/pci/ops-sdk7780.c [deleted file]
arch/sh/drivers/pci/ops-se7780.c [deleted file]
arch/sh/drivers/pci/ops-sh03.c [deleted file]
arch/sh/drivers/pci/ops-sh4.c
arch/sh/drivers/pci/ops-sh5.c
arch/sh/drivers/pci/ops-sh7785lcr.c [deleted file]
arch/sh/drivers/pci/ops-snapgear.c [deleted file]
arch/sh/drivers/pci/pci-auto.c [deleted file]
arch/sh/drivers/pci/pci-dreamcast.c [new file with mode: 0644]
arch/sh/drivers/pci/pci-sh4.h
arch/sh/drivers/pci/pci-sh5.c
arch/sh/drivers/pci/pci-sh5.h
arch/sh/drivers/pci/pci-sh7751.c
arch/sh/drivers/pci/pci-sh7751.h
arch/sh/drivers/pci/pci-sh7780.c
arch/sh/drivers/pci/pci-sh7780.h
arch/sh/drivers/pci/pci.c
arch/sh/include/asm/atomic-llsc.h
arch/sh/include/asm/atomic.h
arch/sh/include/asm/cacheflush.h
arch/sh/include/asm/clock.h
arch/sh/include/asm/cmpxchg-llsc.h
arch/sh/include/asm/device.h
arch/sh/include/asm/hd64461.h
arch/sh/include/asm/io.h
arch/sh/include/asm/irq.h
arch/sh/include/asm/kprobes.h
arch/sh/include/asm/machvec.h
arch/sh/include/asm/pci.h
arch/sh/include/asm/pgtable.h
arch/sh/include/asm/processor.h
arch/sh/include/asm/ptrace.h
arch/sh/include/asm/rtc.h
arch/sh/include/asm/spinlock.h
arch/sh/include/asm/swab.h
arch/sh/include/asm/system_32.h
arch/sh/include/asm/timer.h [deleted file]
arch/sh/include/asm/types.h
arch/sh/include/asm/ubc.h
arch/sh/include/asm/unaligned-sh4a.h
arch/sh/include/asm/unistd_32.h
arch/sh/include/asm/unistd_64.h
arch/sh/include/cpu-sh2a/cpu/ubc.h
arch/sh/include/cpu-sh3/cpu/timer.h [deleted file]
arch/sh/include/cpu-sh4/cpu/cache.h
arch/sh/include/cpu-sh4/cpu/freq.h
arch/sh/include/cpu-sh4/cpu/sh7722.h
arch/sh/include/cpu-sh4/cpu/sh7723.h
arch/sh/include/cpu-sh4/cpu/sh7724.h [new file with mode: 0644]
arch/sh/include/cpu-sh4/cpu/sh7785.h
arch/sh/include/cpu-sh4/cpu/timer.h [deleted file]
arch/sh/include/cpu-sh5/cpu/irq.h
arch/sh/include/mach-common/mach/sh7785lcr.h
arch/sh/include/mach-dreamcast/mach/pci.h
arch/sh/include/mach-se/mach/se7724.h [new file with mode: 0644]
arch/sh/kernel/Makefile_32
arch/sh/kernel/Makefile_64
arch/sh/kernel/cpu/Makefile
arch/sh/kernel/cpu/clock-cpg.c [new file with mode: 0644]
arch/sh/kernel/cpu/clock.c
arch/sh/kernel/cpu/init.c
arch/sh/kernel/cpu/irq/imask.c
arch/sh/kernel/cpu/irq/intc-sh5.c
arch/sh/kernel/cpu/irq/ipr.c
arch/sh/kernel/cpu/sh2/clock-sh7619.c
arch/sh/kernel/cpu/sh2/setup-sh7619.c
arch/sh/kernel/cpu/sh2a/clock-sh7201.c
arch/sh/kernel/cpu/sh2a/clock-sh7203.c
arch/sh/kernel/cpu/sh2a/clock-sh7206.c
arch/sh/kernel/cpu/sh2a/setup-mxg.c
arch/sh/kernel/cpu/sh2a/setup-sh7201.c
arch/sh/kernel/cpu/sh2a/setup-sh7203.c
arch/sh/kernel/cpu/sh2a/setup-sh7206.c
arch/sh/kernel/cpu/sh3/clock-sh3.c
arch/sh/kernel/cpu/sh3/clock-sh7705.c
arch/sh/kernel/cpu/sh3/clock-sh7706.c
arch/sh/kernel/cpu/sh3/clock-sh7709.c
arch/sh/kernel/cpu/sh3/clock-sh7710.c
arch/sh/kernel/cpu/sh3/clock-sh7712.c
arch/sh/kernel/cpu/sh3/setup-sh7705.c
arch/sh/kernel/cpu/sh3/setup-sh770x.c
arch/sh/kernel/cpu/sh3/setup-sh7710.c
arch/sh/kernel/cpu/sh3/setup-sh7720.c
arch/sh/kernel/cpu/sh4/clock-sh4-202.c
arch/sh/kernel/cpu/sh4/clock-sh4.c
arch/sh/kernel/cpu/sh4/probe.c
arch/sh/kernel/cpu/sh4/setup-sh4-202.c
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/cpu/sh4/setup-sh7760.c
arch/sh/kernel/cpu/sh4a/Makefile
arch/sh/kernel/cpu/sh4a/clock-sh7343.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/clock-sh7366.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/clock-sh7722.c
arch/sh/kernel/cpu/sh4a/clock-sh7723.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/clock-sh7724.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/clock-sh7763.c
arch/sh/kernel/cpu/sh4a/clock-sh7770.c
arch/sh/kernel/cpu/sh4a/clock-sh7780.c
arch/sh/kernel/cpu/sh4a/clock-sh7785.c
arch/sh/kernel/cpu/sh4a/clock-sh7786.c
arch/sh/kernel/cpu/sh4a/clock-shx3.c
arch/sh/kernel/cpu/sh4a/pinmux-sh7724.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/setup-sh7343.c
arch/sh/kernel/cpu/sh4a/setup-sh7366.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/cpu/sh4a/setup-sh7724.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/setup-sh7763.c
arch/sh/kernel/cpu/sh4a/setup-sh7770.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-sh7786.c
arch/sh/kernel/cpu/sh4a/setup-shx3.c
arch/sh/kernel/cpu/sh5/Makefile
arch/sh/kernel/cpu/sh5/clock-sh5.c
arch/sh/kernel/cpu/sh5/entry.S
arch/sh/kernel/cpu/sh5/setup-sh5.c [new file with mode: 0644]
arch/sh/kernel/io.c
arch/sh/kernel/io_trapped.c
arch/sh/kernel/irq.c
arch/sh/kernel/kgdb.c
arch/sh/kernel/localtimer.c [moved from arch/sh/kernel/timers/timer-broadcast.c with 100% similarity]
arch/sh/kernel/machvec.c
arch/sh/kernel/module.c
arch/sh/kernel/process_32.c
arch/sh/kernel/ptrace_32.c
arch/sh/kernel/setup.c
arch/sh/kernel/sh_ksyms_32.c
arch/sh/kernel/sh_ksyms_64.c
arch/sh/kernel/syscalls_32.S
arch/sh/kernel/syscalls_64.S
arch/sh/kernel/time.c [new file with mode: 0644]
arch/sh/kernel/time_32.c [deleted file]
arch/sh/kernel/time_64.c [deleted file]
arch/sh/kernel/timers/Makefile [deleted file]
arch/sh/kernel/timers/timer-cmt.c [deleted file]
arch/sh/kernel/timers/timer-mtu2.c [deleted file]
arch/sh/kernel/timers/timer-tmu.c [deleted file]
arch/sh/kernel/timers/timer.c [deleted file]
arch/sh/kernel/traps.c
arch/sh/kernel/traps_32.c
arch/sh/kernel/traps_64.c
arch/sh/kernel/vmlinux.lds.S
arch/sh/kernel/vmlinux_32.lds.S [deleted file]
arch/sh/kernel/vmlinux_64.lds.S [deleted file]
arch/sh/lib64/.gitignore [deleted file]
arch/sh/lib64/dbg.c
arch/sh/lib64/panic.c
arch/sh/lib64/sdivsi3.S
arch/sh/lib64/udelay.c
arch/sh/mm/Kconfig
arch/sh/mm/cache-sh5.c
arch/sh/mm/init.c
arch/sh/mm/ioremap_32.c
arch/sh/mm/ioremap_64.c
arch/sh/mm/mmap.c
arch/sh/oprofile/common.c
arch/sh/tools/mach-types
arch/sparc/include/asm/thread_info_64.h
arch/sparc/kernel/irq_64.c
arch/um/drivers/ubd_kern.c
arch/x86/Kbuild [new file with mode: 0644]
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/Makefile
arch/x86/boot/.gitignore
arch/x86/boot/Makefile
arch/x86/boot/a20.c
arch/x86/boot/apm.c
arch/x86/boot/bioscall.S [new file with mode: 0644]
arch/x86/boot/boot.h
arch/x86/boot/compressed/.gitignore
arch/x86/boot/compressed/Makefile
arch/x86/boot/compressed/head_32.S
arch/x86/boot/compressed/head_64.S
arch/x86/boot/compressed/misc.c
arch/x86/boot/compressed/mkpiggy.c [new file with mode: 0644]
arch/x86/boot/compressed/vmlinux.lds.S [moved from arch/x86/boot/compressed/vmlinux_64.lds with 57% similarity]
arch/x86/boot/compressed/vmlinux.scr [deleted file]
arch/x86/boot/compressed/vmlinux_32.lds [deleted file]
arch/x86/boot/edd.c
arch/x86/boot/header.S
arch/x86/boot/main.c
arch/x86/boot/mca.c
arch/x86/boot/memory.c
arch/x86/boot/regs.c [new file with mode: 0644]
arch/x86/boot/setup.ld
arch/x86/boot/tty.c
arch/x86/boot/video-bios.c
arch/x86/boot/video-vesa.c
arch/x86/boot/video-vga.c
arch/x86/boot/video.c
arch/x86/boot/video.h
arch/x86/configs/i386_defconfig
arch/x86/configs/x86_64_defconfig
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/alternative.h
arch/x86/include/asm/amd_iommu.h
arch/x86/include/asm/amd_iommu_types.h
arch/x86/include/asm/apic.h
arch/x86/include/asm/apicdef.h
arch/x86/include/asm/boot.h
arch/x86/include/asm/bootparam.h
arch/x86/include/asm/cpu_debug.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/ds.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/i387.h
arch/x86/include/asm/i8259.h
arch/x86/include/asm/io_apic.h
arch/x86/include/asm/iomap.h
arch/x86/include/asm/irq_remapping.h
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/k8.h
arch/x86/include/asm/kvm.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/kvm_x86_emulate.h
arch/x86/include/asm/microcode.h
arch/x86/include/asm/mpspec.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/msr.h
arch/x86/include/asm/nmi.h
arch/x86/include/asm/numa_64.h
arch/x86/include/asm/page_32_types.h
arch/x86/include/asm/page_64_types.h
arch/x86/include/asm/page_types.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_64.h
arch/x86/include/asm/pgtable_64_types.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/required-features.h
arch/x86/include/asm/setup.h
arch/x86/include/asm/smp.h
arch/x86/include/asm/sparsemem.h
arch/x86/include/asm/svm.h
arch/x86/include/asm/syscalls.h
arch/x86/include/asm/termios.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/tlbflush.h
arch/x86/include/asm/topology.h
arch/x86/include/asm/traps.h
arch/x86/include/asm/unistd_32.h
arch/x86/include/asm/unistd_64.h
arch/x86/include/asm/uv/uv_bau.h
arch/x86/include/asm/uv/uv_hub.h
arch/x86/include/asm/vmx.h
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/acpi/realmode/Makefile
arch/x86/kernel/acpi/realmode/bioscall.S [new file with mode: 0644]
arch/x86/kernel/acpi/realmode/regs.c [new file with mode: 0644]
arch/x86/kernel/amd_iommu.c
arch/x86/kernel/amd_iommu_init.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/apic_flat_64.c
arch/x86/kernel/apic/es7000_32.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/nmi.c
arch/x86/kernel/apic/probe_32.c
arch/x86/kernel/apic/probe_64.c
arch/x86/kernel/apic/summit_32.c
arch/x86/kernel/apic/x2apic_cluster.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/asm-offsets_32.c
arch/x86/kernel/asm-offsets_64.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpu_debug.c
arch/x86/kernel/cpu/cpufreq/Kconfig
arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce_64.c
arch/x86/kernel/cpu/mcheck/mce_intel_64.c
arch/x86/kernel/cpu/mtrr/cleanup.c
arch/x86/kernel/cpu/mtrr/generic.c
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/cpu/mtrr/mtrr.h
arch/x86/kernel/cpu/mtrr/state.c
arch/x86/kernel/ds.c
arch/x86/kernel/ds_selftest.c [new file with mode: 0644]
arch/x86/kernel/ds_selftest.h [new file with mode: 0644]
arch/x86/kernel/dumpstack.h
arch/x86/kernel/e820.c
arch/x86/kernel/early-quirks.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/head_32.S
arch/x86/kernel/irq.c
arch/x86/kernel/irqinit.c [moved from arch/x86/kernel/irqinit_32.c with 68% similarity]
arch/x86/kernel/irqinit_64.c [deleted file]
arch/x86/kernel/kgdb.c
arch/x86/kernel/kvm.c
arch/x86/kernel/microcode_amd.c
arch/x86/kernel/microcode_core.c
arch/x86/kernel/microcode_intel.c
arch/x86/kernel/mpparse.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/pci-calgary_64.c
arch/x86/kernel/pci-gart_64.c
arch/x86/kernel/pci-swiotlb.c
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/quirks.c
arch/x86/kernel/reboot.c
arch/x86/kernel/setup.c
arch/x86/kernel/setup_percpu.c
arch/x86/kernel/smp.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/stacktrace.c
arch/x86/kernel/syscall_table_32.S
arch/x86/kernel/tlb_uv.c
arch/x86/kernel/traps.c
arch/x86/kernel/tsc.c
arch/x86/kernel/tsc_sync.c
arch/x86/kernel/vm86_32.c
arch/x86/kernel/vmi_32.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/kernel/vmlinux_32.lds.S [deleted file]
arch/x86/kernel/vmlinux_64.lds.S [deleted file]
arch/x86/kernel/vsyscall_64.c
arch/x86/kvm/Kconfig
arch/x86/kvm/Makefile
arch/x86/kvm/i8254.c
arch/x86/kvm/i8254.h
arch/x86/kvm/irq.c
arch/x86/kvm/kvm_timer.h [new file with mode: 0644]
arch/x86/kvm/lapic.c
arch/x86/kvm/lapic.h
arch/x86/kvm/mmu.c
arch/x86/kvm/mmu.h
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/svm.c
arch/x86/kvm/timer.c [new file with mode: 0644]
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/kvm/x86_emulate.c
arch/x86/lguest/boot.c
arch/x86/lib/Makefile
arch/x86/lib/msr-on-cpu.c [deleted file]
arch/x86/lib/msr.c [new file with mode: 0644]
arch/x86/mm/dump_pagetables.c
arch/x86/mm/fault.c
arch/x86/mm/highmem_32.c
arch/x86/mm/init.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/iomap_32.c
arch/x86/mm/kmmio.c
arch/x86/mm/memtest.c
arch/x86/mm/mmio-mod.c
arch/x86/mm/numa_64.c
arch/x86/mm/pageattr.c
arch/x86/mm/srat_64.c
arch/x86/oprofile/nmi_int.c
arch/x86/pci/irq.c
arch/x86/vdso/vma.c
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
arch/x86/xen/setup.c
arch/x86/xen/xen-ops.h
block/Kconfig
block/as-iosched.c
block/blk-barrier.c
block/blk-core.c
block/blk-exec.c
block/blk-integrity.c
block/blk-ioc.c
block/blk-map.c
block/blk-merge.c
block/blk-settings.c
block/blk-sysfs.c
block/blk-tag.c
block/blk-timeout.c
block/blk.h
block/bsg.c
block/cfq-iosched.c
block/compat_ioctl.c
block/deadline-iosched.c
block/elevator.c
block/genhd.c
block/ioctl.c
block/scsi_ioctl.c
drivers/acpi/pci_irq.c
drivers/ata/libata-scsi.c
drivers/block/DAC960.c
drivers/block/Kconfig
drivers/block/amiflop.c
drivers/block/ataflop.c
drivers/block/brd.c
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cciss_cmd.h
drivers/block/cciss_scsi.c
drivers/block/cpqarray.c
drivers/block/floppy.c
drivers/block/hd.c
drivers/block/loop.c
drivers/block/mg_disk.c
drivers/block/nbd.c
drivers/block/paride/pcd.c
drivers/block/paride/pd.c
drivers/block/paride/pf.c
drivers/block/pktcdvd.c
drivers/block/ps3disk.c
drivers/block/sunvdc.c
drivers/block/swim.c
drivers/block/swim3.c
drivers/block/sx8.c
drivers/block/ub.c
drivers/block/viodasd.c
drivers/block/virtio_blk.c
drivers/block/xd.c
drivers/block/xen-blkfront.c
drivers/block/xsysace.c
drivers/block/z2ram.c
drivers/bluetooth/hci_ldisc.c
drivers/cdrom/cdrom.c
drivers/cdrom/gdrom.c
drivers/cdrom/viocd.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/bfin_jtag_comm.c [new file with mode: 0644]
drivers/char/cyclades.c
drivers/char/epca.c
drivers/char/hpet.c
drivers/char/ip2/i2lib.c
drivers/char/ip2/ip2main.c
drivers/char/isicom.c
drivers/char/istallion.c
drivers/char/mem.c
drivers/char/moxa.c
drivers/char/mxser.c
drivers/char/n_hdlc.c
drivers/char/n_tty.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/pty.c
drivers/char/raw.c
drivers/char/rocket.c
drivers/char/selection.c
drivers/char/stallion.c
drivers/char/synclink.c
drivers/char/synclink_gt.c
drivers/char/synclinkmp.c
drivers/char/tty_audit.c
drivers/char/tty_io.c
drivers/char/tty_ioctl.c
drivers/char/tty_ldisc.c
drivers/char/tty_port.c
drivers/clocksource/Makefile
drivers/clocksource/sh_cmt.c
drivers/clocksource/sh_mtu2.c [new file with mode: 0644]
drivers/clocksource/sh_tmu.c [new file with mode: 0644]
drivers/edac/Kconfig
drivers/edac/Makefile
drivers/edac/amd64_edac.c [new file with mode: 0644]
drivers/edac/amd64_edac.h [new file with mode: 0644]
drivers/edac/amd64_edac_dbg.c [new file with mode: 0644]
drivers/edac/amd64_edac_err_types.c [new file with mode: 0644]
drivers/edac/amd64_edac_inj.c [new file with mode: 0644]
drivers/edac/edac_core.h
drivers/i2c/busses/i2c-sh7760.c
drivers/ide/alim15x3.c
drivers/ide/ide-atapi.c
drivers/ide/ide-cd.c
drivers/ide/ide-cd.h
drivers/ide/ide-disk.c
drivers/ide/ide-dma.c
drivers/ide/ide-floppy.c
drivers/ide/ide-io.c
drivers/ide/ide-ioctls.c
drivers/ide/ide-lib.c
drivers/ide/ide-park.c
drivers/ide/ide-pm.c
drivers/ide/ide-tape.c
drivers/ide/ide-taskfile.c
drivers/ide/pdc202xx_old.c
drivers/ide/tc86c001.c
drivers/ide/tx4939ide.c
drivers/md/bitmap.c
drivers/md/dm-exception-store.c
drivers/md/dm-log.c
drivers/md/dm-snap-persistent.c
drivers/md/dm-table.c
drivers/md/dm.c
drivers/md/linear.c
drivers/md/md.c
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/memstick/core/mspro_block.c
drivers/message/fusion/mptsas.c
drivers/message/i2o/i2o_block.c
drivers/mmc/card/block.c
drivers/mmc/card/queue.c
drivers/mtd/mtd_blkdevs.c
drivers/parisc/iosapic.c
drivers/parport/parport_pc.c
drivers/pci/hotplug/ibmphp_core.c
drivers/pci/htirq.c
drivers/pci/intel-iommu.c
drivers/pci/intr_remapping.c
drivers/pnp/pnpacpi/rsparser.c
drivers/rtc/Kconfig
drivers/s390/block/dasd.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dcssblk.c
drivers/s390/block/xpram.c
drivers/s390/char/tape_34xx.c
drivers/s390/char/tape_3590.c
drivers/s390/char/tape_block.c
drivers/sbus/char/jsflash.c
drivers/scsi/eata.c
drivers/scsi/libsas/sas_expander.c
drivers/scsi/libsas/sas_host_smp.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/mpt2sas/mpt2sas_transport.c
drivers/scsi/osd/osd_initiator.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_tgt_lib.c
drivers/scsi/scsi_transport_sas.c
drivers/scsi/sd.c
drivers/scsi/sd_dif.c
drivers/scsi/sg.c
drivers/scsi/sr.c
drivers/scsi/st.c
drivers/scsi/u14-34f.c
drivers/serial/8250.c
drivers/serial/8250_pci.c
drivers/serial/Kconfig
drivers/serial/Makefile
drivers/serial/bfin_5xx.c
drivers/serial/bfin_sport_uart.c
drivers/serial/icom.c
drivers/serial/imx.c
drivers/serial/jsm/jsm.h
drivers/serial/jsm/jsm_tty.c
drivers/serial/sh-sci.c
drivers/serial/sh-sci.h
drivers/serial/timbuart.c [new file with mode: 0644]
drivers/serial/timbuart.h [new file with mode: 0644]
drivers/sh/intc.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-acm.h
drivers/usb/serial/belkin_sa.c
drivers/usb/serial/ch341.c
drivers/usb/serial/console.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/cyberjack.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/empeg.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/garmin_gps.c
drivers/usb/serial/generic.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_ti.c
drivers/usb/serial/ipaq.c
drivers/usb/serial/ipw.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan.h
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/navman.c
drivers/usb/serial/omninet.c
drivers/usb/serial/opticon.c
drivers/usb/serial/option.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/sierra.c
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/symbolserial.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/visor.c
drivers/usb/serial/whiteheat.c
drivers/usb/storage/scsiglue.c
drivers/video/hitfb.c
drivers/xen/Kconfig
drivers/xen/Makefile
drivers/xen/events.c
drivers/xen/evtchn.c [new file with mode: 0644]
drivers/xen/manage.c
drivers/xen/sys-hypervisor.c [new file with mode: 0644]
drivers/xen/xenbus/xenbus_probe.c
drivers/xen/xenbus/xenbus_xs.c
drivers/xen/xenfs/super.c
fs/bio.c
fs/block_dev.c
fs/buffer.c
fs/cifs/CHANGES
fs/cifs/README
fs/cifs/cifs_spnego.c
fs/cifs/cifsacl.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/netmisc.c
fs/cifs/readdir.c
fs/coda/file.c
fs/compat.c
fs/devpts/inode.c
fs/direct-io.c
fs/exec.c
fs/exofs/osd.c
fs/ext2/super.c
fs/ext3/super.c
fs/ext4/Makefile
fs/ext4/balloc.c
fs/ext4/block_validity.c [new file with mode: 0644]
fs/ext4/dir.c
fs/ext4/ext4.h
fs/ext4/ext4_i.h [deleted file]
fs/ext4/ext4_sb.h [deleted file]
fs/ext4/extents.c
fs/ext4/group.h [deleted file]
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/mballoc.h
fs/ext4/namei.c
fs/ext4/namei.h [deleted file]
fs/ext4/resize.c
fs/ext4/super.c
fs/gfs2/Kconfig
fs/gfs2/Makefile
fs/gfs2/aops.c [moved from fs/gfs2/ops_address.c with 98% similarity]
fs/gfs2/bmap.c
fs/gfs2/dentry.c [moved from fs/gfs2/ops_dentry.c with 100% similarity]
fs/gfs2/dir.c
fs/gfs2/eattr.c
fs/gfs2/export.c [moved from fs/gfs2/ops_export.c with 100% similarity]
fs/gfs2/file.c [moved from fs/gfs2/ops_file.c with 97% similarity]
fs/gfs2/glock.c
fs/gfs2/glops.c
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/inode.h
fs/gfs2/log.c
fs/gfs2/lops.c
fs/gfs2/main.c
fs/gfs2/meta_io.c
fs/gfs2/mount.c [deleted file]
fs/gfs2/ops_address.h [deleted file]
fs/gfs2/ops_fstype.c
fs/gfs2/ops_inode.c
fs/gfs2/ops_super.c [deleted file]
fs/gfs2/quota.c
fs/gfs2/recovery.c
fs/gfs2/recovery.h
fs/gfs2/rgrp.c
fs/gfs2/rgrp.h
fs/gfs2/super.c
fs/gfs2/sys.c
fs/gfs2/trans.c
fs/hugetlbfs/inode.c
fs/ioctl.c
fs/jbd2/journal.c
fs/mpage.c
fs/namei.c
fs/nfsd/vfs.c
fs/nilfs2/the_nilfs.c
fs/ntfs/super.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/super.c
fs/partitions/check.c
fs/partitions/ibm.c
fs/partitions/msdos.c
fs/pipe.c
fs/proc/base.c
fs/proc/loadavg.c
fs/read_write.c
fs/splice.c
fs/udf/super.c
fs/xfs/linux-2.6/xfs_buf.c
include/Kbuild
include/asm-generic/pgtable.h
include/asm-generic/vmlinux.lds.h
include/linux/acpi.h
include/linux/bio.h
include/linux/blkdev.h
include/linux/blktrace_api.h
include/linux/clocksource.h
include/linux/compat.h
include/linux/cyclades.h
include/linux/device-mapper.h
include/linux/dma-debug.h
include/linux/dmar.h
include/linux/elevator.h
include/linux/fs.h
include/linux/ftrace.h
include/linux/ftrace_event.h [new file with mode: 0644]
include/linux/futex.h
include/linux/genhd.h
include/linux/ide.h
include/linux/ima.h
include/linux/init_task.h
include/linux/interrupt.h
include/linux/iocontext.h
include/linux/irq.h
include/linux/kmemtrace.h [new file with mode: 0644]
include/linux/kvm.h
include/linux/kvm_host.h
include/linux/kvm_types.h
include/linux/loop.h
include/linux/lsm_audit.h [new file with mode: 0644]
include/linux/magic.h
include/linux/mg_disk.h [deleted file]
include/linux/mm.h
include/linux/mmiotrace.h
include/linux/module.h
include/linux/mutex.h
include/linux/pci_ids.h
include/linux/pipe_fs_i.h
include/linux/ptrace.h
include/linux/rational.h [new file with mode: 0644]
include/linux/rculist.h
include/linux/rcutree.h
include/linux/ring_buffer.h
include/linux/sched.h
include/linux/security.h
include/linux/serial.h
include/linux/serial_core.h
include/linux/serial_sci.h
include/linux/sh_cmt.h [deleted file]
include/linux/sh_timer.h [new file with mode: 0644]
include/linux/signal.h
include/linux/slab_def.h
include/linux/slub_def.h
include/linux/spinlock_up.h
include/linux/splice.h
include/linux/swiotlb.h
include/linux/thread_info.h
include/linux/time.h
include/linux/trace_seq.h [new file with mode: 0644]
include/linux/tracepoint.h
include/linux/tty.h
include/linux/tty_driver.h
include/linux/usb/serial.h
include/linux/virtio_blk.h
include/linux/wait.h
include/scsi/scsi_cmnd.h
include/trace/block.h [deleted file]
include/trace/define_trace.h [new file with mode: 0644]
include/trace/events/block.h [new file with mode: 0644]
include/trace/events/irq.h [new file with mode: 0644]
include/trace/events/kmem.h [new file with mode: 0644]
include/trace/events/lockdep.h [new file with mode: 0644]
include/trace/events/sched.h [moved from include/trace/sched_event_types.h with 91% similarity]
include/trace/events/skb.h [new file with mode: 0644]
include/trace/events/workqueue.h [new file with mode: 0644]
include/trace/ftrace.h [new file with mode: 0644]
include/trace/irq.h [deleted file]
include/trace/irq_event_types.h [deleted file]
include/trace/kmemtrace.h [deleted file]
include/trace/lockdep.h [deleted file]
include/trace/lockdep_event_types.h [deleted file]
include/trace/sched.h [deleted file]
include/trace/skb.h [deleted file]
include/trace/trace_event_types.h [deleted file]
include/trace/trace_events.h [deleted file]
include/trace/workqueue.h [deleted file]
include/xen/Kbuild [new file with mode: 0644]
include/xen/events.h
include/xen/evtchn.h [new file with mode: 0644]
include/xen/interface/version.h
include/xen/xenbus.h
init/Kconfig
init/main.c
ipc/sem.c
ipc/shm.c
kernel/Makefile
kernel/compat.c
kernel/cred.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/irq/Makefile
kernel/irq/chip.c
kernel/irq/handle.c
kernel/irq/internals.h
kernel/irq/manage.c
kernel/irq/migration.c
kernel/irq/numa_migrate.c
kernel/kthread.c
kernel/lockdep.c
kernel/module.c
kernel/mutex.c
kernel/ptrace.c
kernel/rcupreempt.c
kernel/rcutree.c
kernel/rcutree_trace.c
kernel/rtmutex.c
kernel/rtmutex_common.h
kernel/sched.c
kernel/sched_fair.c
kernel/sched_idletask.c
kernel/signal.c
kernel/softirq.c
kernel/sysctl.c
kernel/time/clocksource.c
kernel/time/timekeeping.c
kernel/timer.c
kernel/trace/Kconfig
kernel/trace/Makefile
kernel/trace/blktrace.c
kernel/trace/events.c [deleted file]
kernel/trace/ftrace.c
kernel/trace/kmemtrace.c
kernel/trace/ring_buffer.c
kernel/trace/ring_buffer_benchmark.c [new file with mode: 0644]
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_boot.c
kernel/trace/trace_branch.c
kernel/trace/trace_event_profile.c
kernel/trace/trace_event_types.h
kernel/trace/trace_events.c
kernel/trace/trace_events_filter.c
kernel/trace/trace_events_stage_1.h [deleted file]
kernel/trace/trace_events_stage_2.h [deleted file]
kernel/trace/trace_events_stage_3.h [deleted file]
kernel/trace/trace_export.c
kernel/trace/trace_functions_graph.c
kernel/trace/trace_hw_branches.c
kernel/trace/trace_mmiotrace.c
kernel/trace/trace_output.c
kernel/trace/trace_output.h
kernel/trace/trace_power.c
kernel/trace/trace_printk.c
kernel/trace/trace_sched_switch.c
kernel/trace/trace_sched_wakeup.c
kernel/trace/trace_selftest.c
kernel/trace/trace_stack.c
kernel/trace/trace_stat.c
kernel/trace/trace_stat.h
kernel/trace/trace_sysprof.c
kernel/trace/trace_workqueue.c
kernel/wait.c
kernel/workqueue.c
lib/Kconfig
lib/Makefile
lib/dma-debug.c
lib/rational.c [new file with mode: 0644]
lib/swiotlb.c
lib/vsprintf.c
mm/Kconfig
mm/bounce.c
mm/mlock.c
mm/mmap.c
mm/nommu.c
mm/page_alloc.c
mm/percpu.c
mm/shmem.c
mm/slab.c
mm/slob.c
mm/slub.c
mm/util.c
net/core/drop_monitor.c
net/core/net-traces.c
net/core/skbuff.c
samples/Kconfig
samples/Makefile
samples/trace_events/Makefile [new file with mode: 0644]
samples/trace_events/trace-events-sample.c [new file with mode: 0644]
samples/trace_events/trace-events-sample.h [new file with mode: 0644]
scripts/Makefile.lib
scripts/bin_size [deleted file]
scripts/kernel-doc
scripts/recordmcount.pl
security/Kconfig
security/Makefile
security/commoncap.c
security/inode.c
security/integrity/ima/ima_audit.c
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_fs.c
security/integrity/ima/ima_iint.c
security/integrity/ima/ima_init.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c
security/lsm_audit.c [new file with mode: 0644]
security/root_plug.c
security/security.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/security.h
security/selinux/nlmsgtab.c
security/selinux/selinuxfs.c
security/selinux/ss/services.c
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c
security/tomoyo/common.c
security/tomoyo/common.h
security/tomoyo/domain.c
security/tomoyo/file.c
security/tomoyo/realpath.c
security/tomoyo/tomoyo.c
security/tomoyo/tomoyo.h
sound/oss/Kconfig
sound/oss/sh_dac_audio.c
virt/kvm/ioapic.c
virt/kvm/ioapic.h
virt/kvm/iommu.c
virt/kvm/irq_comm.c
virt/kvm/kvm_main.c

index 44f52a4f5903359eda2f2ffafff2d3341e437e62..cbbd3e0699453391a461bff35431df5f0ee0d53e 100644 (file)
@@ -60,3 +60,62 @@ Description:
                Indicates whether the block layer should automatically
                generate checksums for write requests bound for
                devices that support receiving integrity metadata.
+
+What:          /sys/block/<disk>/alignment_offset
+Date:          April 2009
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Storage devices may report a physical block size that is
+               bigger than the logical block size (for instance a drive
+               with 4KB physical sectors exposing 512-byte logical
+               blocks to the operating system).  This parameter
+               indicates how many bytes the beginning of the device is
+               offset from the disk's natural alignment.
+
+What:          /sys/block/<disk>/<partition>/alignment_offset
+Date:          April 2009
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Storage devices may report a physical block size that is
+               bigger than the logical block size (for instance a drive
+               with 4KB physical sectors exposing 512-byte logical
+               blocks to the operating system).  This parameter
+               indicates how many bytes the beginning of the partition
+               is offset from the disk's natural alignment.
+
+What:          /sys/block/<disk>/queue/logical_block_size
+Date:          May 2009
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               This is the smallest unit the storage device can
+               address.  It is typically 512 bytes.
+
+What:          /sys/block/<disk>/queue/physical_block_size
+Date:          May 2009
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               This is the smallest unit the storage device can write
+               without resorting to read-modify-write operation.  It is
+               usually the same as the logical block size but may be
+               bigger.  One example is SATA drives with 4KB sectors
+               that expose a 512-byte logical block size to the
+               operating system.
+
+What:          /sys/block/<disk>/queue/minimum_io_size
+Date:          April 2009
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Storage devices may report a preferred minimum I/O size,
+               which is the smallest request the device can perform
+               without incurring a read-modify-write penalty.  For disk
+               drives this is often the physical block size.  For RAID
+               arrays it is often the stripe chunk size.
+
+What:          /sys/block/<disk>/queue/optimal_io_size
+Date:          April 2009
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Storage devices may report an optimal I/O size, which is
+               the device's preferred unit of receiving I/O.  This is
+               rarely reported for disk drives.  For RAID devices it is
+               usually the stripe width or the internal block size.
diff --git a/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss
new file mode 100644 (file)
index 0000000..0a92a7c
--- /dev/null
@@ -0,0 +1,33 @@
+Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/model
+Date:          March 2009
+Kernel Version: 2.6.30
+Contact:       iss_storagedev@hp.com
+Description:   Displays the SCSI INQUIRY page 0 model for logical drive
+               Y of controller X.
+
+Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/rev
+Date:          March 2009
+Kernel Version: 2.6.30
+Contact:       iss_storagedev@hp.com
+Description:   Displays the SCSI INQUIRY page 0 revision for logical
+               drive Y of controller X.
+
+Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/unique_id
+Date:          March 2009
+Kernel Version: 2.6.30
+Contact:       iss_storagedev@hp.com
+Description:   Displays the SCSI INQUIRY page 83 serial number for logical
+               drive Y of controller X.
+
+Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/vendor
+Date:          March 2009
+Kernel Version: 2.6.30
+Contact:       iss_storagedev@hp.com
+Description:   Displays the SCSI INQUIRY page 0 vendor for logical drive
+               Y of controller X.
+
+Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/block:cciss!cXdY
+Date:          March 2009
+Kernel Version: 2.6.30
+Contact:       iss_storagedev@hp.com
+Description:   A symbolic link to /sys/block/cciss!cXdY
diff --git a/Documentation/ABI/testing/sysfs-devices-cache_disable b/Documentation/ABI/testing/sysfs-devices-cache_disable
new file mode 100644 (file)
index 0000000..175bb4f
--- /dev/null
@@ -0,0 +1,18 @@
+What:      /sys/devices/system/cpu/cpu*/cache/index*/cache_disable_X
+Date:      August 2008
+KernelVersion: 2.6.27
+Contact:       mark.langsdorf@amd.com
+Description:   These files exist in every cpu's cache index directories.
+               There are currently 2 cache_disable_# files in each
+               directory.  Reading from these files on a supported
+               processor will return that cache disable index value
+               for that processor and node.  Writing to one of these
+               files will cause the specificed cache index to be disabled.
+
+               Currently, only AMD Family 10h Processors support cache index
+               disable, and only for their L3 caches.  See the BIOS and
+               Kernel Developer's Guide at
+               http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/31116-Public-GH-BKDG_3.20_2-4-09.pdf
+               for formatting information and other details on the
+               cache index disable.
+Users:    joachim.deguara@amd.com
index d9aa43d78bcc9fc92e582a62cadb18cd9b27f4f0..25fb8bcf32a276f280d44aa53a4f2712a14257f4 100644 (file)
@@ -704,12 +704,24 @@ this directory the following files can currently be found:
                                The current number of free dma_debug_entries
                                in the allocator.
 
+       dma-api/driver-filter
+                               You can write a name of a driver into this file
+                               to limit the debug output to requests from that
+                               particular driver. Write an empty string to
+                               that file to disable the filter and see
+                               all errors again.
+
 If you have this code compiled into your kernel it will be enabled by default.
 If you want to boot without the bookkeeping anyway you can provide
 'dma_debug=off' as a boot parameter. This will disable DMA-API debugging.
 Notice that you can not enable it again at runtime. You have to reboot to do
 so.
 
+If you want to see debug messages only for a special device driver you can
+specify the dma_debug_driver=<drivername> parameter. This will enable the
+driver filter at boot time. The debug code will only print errors for that
+driver afterwards. This filter can be disabled or changed later using debugfs.
+
 When the code disables itself at runtime this is most likely because it ran
 out of dma_debug_entries. These entries are preallocated at boot. The number
 of preallocated entries is defined per architecture. If it is too low for you
index b1eb661e6302a3e5aeae0a58d3cda169f46f66a2..9632444f6c6270b87894e2381f95985ed3126d7a 100644 (file)
@@ -13,7 +13,8 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
            gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
            genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
            mac80211.xml debugobjects.xml sh.xml regulator.xml \
-           alsa-driver-api.xml writing-an-alsa-driver.xml
+           alsa-driver-api.xml writing-an-alsa-driver.xml \
+           tracepoint.xml
 
 ###
 # The build process is as follows (targets):
diff --git a/Documentation/DocBook/tracepoint.tmpl b/Documentation/DocBook/tracepoint.tmpl
new file mode 100644 (file)
index 0000000..b0756d0
--- /dev/null
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="Tracepoints">
+ <bookinfo>
+  <title>The Linux Kernel Tracepoint API</title>
+
+  <authorgroup>
+   <author>
+    <firstname>Jason</firstname>
+    <surname>Baron</surname>
+    <affiliation>
+     <address>
+      <email>jbaron@redhat.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <legalnotice>
+   <para>
+     This documentation 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.
+   </para>
+
+   <para>
+     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.
+   </para>
+
+   <para>
+     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
+   </para>
+
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+ <toc></toc>
+  <chapter id="intro">
+   <title>Introduction</title>
+   <para>
+     Tracepoints are static probe points that are located in strategic points
+     throughout the kernel. 'Probes' register/unregister with tracepoints
+     via a callback mechanism. The 'probes' are strictly typed functions that
+     are passed a unique set of parameters defined by each tracepoint.
+   </para>
+
+   <para>
+     From this simple callback mechanism, 'probes' can be used to profile, debug,
+     and understand kernel behavior. There are a number of tools that provide a
+     framework for using 'probes'. These tools include Systemtap, ftrace, and
+     LTTng.
+   </para>
+
+   <para>
+     Tracepoints are defined in a number of header files via various macros. Thus,
+     the purpose of this document is to provide a clear accounting of the available
+     tracepoints. The intention is to understand not only what tracepoints are
+     available but also to understand where future tracepoints might be added.
+   </para>
+
+   <para>
+     The API presented has functions of the form:
+     <function>trace_tracepointname(function parameters)</function>. These are the
+     tracepoints callbacks that are found throughout the code. Registering and
+     unregistering probes with these callback sites is covered in the
+     <filename>Documentation/trace/*</filename> directory.
+   </para>
+  </chapter>
+
+  <chapter id="irq">
+   <title>IRQ</title>
+!Iinclude/trace/events/irq.h
+  </chapter>
+
+</book>
index 068848240a8bdf135ba706da5c3d01a43609397a..02cced183b2d63f81428b3d6a21064397c7a7533 100644 (file)
@@ -192,23 +192,24 @@ rcu/rcuhier (which displays the struct rcu_node hierarchy).
 The output of "cat rcu/rcudata" looks as follows:
 
 rcu:
-  0 c=4011 g=4012 pq=1 pqc=4011 qp=0 rpfq=1 rp=3c2a dt=23301/73 dn=2 df=1882 of=0 ri=2126 ql=2 b=10
-  1 c=4011 g=4012 pq=1 pqc=4011 qp=0 rpfq=3 rp=39a6 dt=78073/1 dn=2 df=1402 of=0 ri=1875 ql=46 b=10
-  2 c=4010 g=4010 pq=1 pqc=4010 qp=0 rpfq=-5 rp=1d12 dt=16646/0 dn=2 df=3140 of=0 ri=2080 ql=0 b=10
-  3 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=2b50 dt=21159/1 dn=2 df=2230 of=0 ri=1923 ql=72 b=10
-  4 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=1644 dt=5783/1 dn=2 df=3348 of=0 ri=2805 ql=7 b=10
-  5 c=4012 g=4013 pq=0 pqc=4011 qp=1 rpfq=3 rp=1aac dt=5879/1 dn=2 df=3140 of=0 ri=2066 ql=10 b=10
-  6 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=ed8 dt=5847/1 dn=2 df=3797 of=0 ri=1266 ql=10 b=10
-  7 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=1fa2 dt=6199/1 dn=2 df=2795 of=0 ri=2162 ql=28 b=10
+rcu:
+  0 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=10951/1 dn=0 df=1101 of=0 ri=36 ql=0 b=10
+  1 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=16117/1 dn=0 df=1015 of=0 ri=0 ql=0 b=10
+  2 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1445/1 dn=0 df=1839 of=0 ri=0 ql=0 b=10
+  3 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=6681/1 dn=0 df=1545 of=0 ri=0 ql=0 b=10
+  4 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1003/1 dn=0 df=1992 of=0 ri=0 ql=0 b=10
+  5 c=17829 g=17830 pq=1 pqc=17829 qp=1 dt=3887/1 dn=0 df=3331 of=0 ri=4 ql=2 b=10
+  6 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=859/1 dn=0 df=3224 of=0 ri=0 ql=0 b=10
+  7 c=17829 g=17830 pq=0 pqc=17829 qp=1 dt=3761/1 dn=0 df=1818 of=0 ri=0 ql=2 b=10
 rcu_bh:
-  0 c=-268 g=-268 pq=1 pqc=-268 qp=0 rpfq=-145 rp=21d6 dt=23301/73 dn=2 df=0 of=0 ri=0 ql=0 b=10
-  1 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-170 rp=20ce dt=78073/1 dn=2 df=26 of=0 ri=5 ql=0 b=10
-  2 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-83 rp=fbd dt=16646/0 dn=2 df=28 of=0 ri=4 ql=0 b=10
-  3 c=-268 g=-268 pq=1 pqc=-268 qp=0 rpfq=-105 rp=178c dt=21159/1 dn=2 df=28 of=0 ri=2 ql=0 b=10
-  4 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-30 rp=b54 dt=5783/1 dn=2 df=32 of=0 ri=0 ql=0 b=10
-  5 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-29 rp=df5 dt=5879/1 dn=2 df=30 of=0 ri=3 ql=0 b=10
-  6 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-28 rp=788 dt=5847/1 dn=2 df=32 of=0 ri=0 ql=0 b=10
-  7 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-53 rp=1098 dt=6199/1 dn=2 df=30 of=0 ri=3 ql=0 b=10
+  0 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=10951/1 dn=0 df=0 of=0 ri=0 ql=0 b=10
+  1 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=16117/1 dn=0 df=13 of=0 ri=0 ql=0 b=10
+  2 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1445/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
+  3 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=6681/1 dn=0 df=9 of=0 ri=0 ql=0 b=10
+  4 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1003/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
+  5 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3887/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
+  6 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=859/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
+  7 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3761/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
 
 The first section lists the rcu_data structures for rcu, the second for
 rcu_bh.  Each section has one line per CPU, or eight for this 8-CPU system.
@@ -253,12 +254,6 @@ o  "pqc" indicates which grace period the last-observed quiescent
 o      "qp" indicates that RCU still expects a quiescent state from
        this CPU.
 
-o      "rpfq" is the number of rcu_pending() calls on this CPU required
-       to induce this CPU to invoke force_quiescent_state().
-
-o      "rp" is low-order four hex digits of the count of how many times
-       rcu_pending() has been invoked on this CPU.
-
 o      "dt" is the current value of the dyntick counter that is incremented
        when entering or leaving dynticks idle state, either by the
        scheduler or by irq.  The number after the "/" is the interrupt
@@ -305,6 +300,9 @@ o   "b" is the batch limit for this CPU.  If more than this number
        of RCU callbacks is ready to invoke, then the remainder will
        be deferred.
 
+There is also an rcu/rcudata.csv file with the same information in
+comma-separated-variable spreadsheet format.
+
 
 The output of "cat rcu/rcugp" looks as follows:
 
@@ -411,3 +409,63 @@ o  Each element of the form "1/1 0:127 ^0" represents one struct
                For example, the first entry at the lowest level shows
                "^0", indicating that it corresponds to bit zero in
                the first entry at the middle level.
+
+
+The output of "cat rcu/rcu_pending" looks as follows:
+
+rcu:
+  0 np=255892 qsp=53936 cbr=0 cng=14417 gpc=10033 gps=24320 nf=6445 nn=146741
+  1 np=261224 qsp=54638 cbr=0 cng=25723 gpc=16310 gps=2849 nf=5912 nn=155792
+  2 np=237496 qsp=49664 cbr=0 cng=2762 gpc=45478 gps=1762 nf=1201 nn=136629
+  3 np=236249 qsp=48766 cbr=0 cng=286 gpc=48049 gps=1218 nf=207 nn=137723
+  4 np=221310 qsp=46850 cbr=0 cng=26 gpc=43161 gps=4634 nf=3529 nn=123110
+  5 np=237332 qsp=48449 cbr=0 cng=54 gpc=47920 gps=3252 nf=201 nn=137456
+  6 np=219995 qsp=46718 cbr=0 cng=50 gpc=42098 gps=6093 nf=4202 nn=120834
+  7 np=249893 qsp=49390 cbr=0 cng=72 gpc=38400 gps=17102 nf=41 nn=144888
+rcu_bh:
+  0 np=146741 qsp=1419 cbr=0 cng=6 gpc=0 gps=0 nf=2 nn=145314
+  1 np=155792 qsp=12597 cbr=0 cng=0 gpc=4 gps=8 nf=3 nn=143180
+  2 np=136629 qsp=18680 cbr=0 cng=0 gpc=7 gps=6 nf=0 nn=117936
+  3 np=137723 qsp=2843 cbr=0 cng=0 gpc=10 gps=7 nf=0 nn=134863
+  4 np=123110 qsp=12433 cbr=0 cng=0 gpc=4 gps=2 nf=0 nn=110671
+  5 np=137456 qsp=4210 cbr=0 cng=0 gpc=6 gps=5 nf=0 nn=133235
+  6 np=120834 qsp=9902 cbr=0 cng=0 gpc=6 gps=3 nf=2 nn=110921
+  7 np=144888 qsp=26336 cbr=0 cng=0 gpc=8 gps=2 nf=0 nn=118542
+
+As always, this is once again split into "rcu" and "rcu_bh" portions.
+The fields are as follows:
+
+o      "np" is the number of times that __rcu_pending() has been invoked
+       for the corresponding flavor of RCU.
+
+o      "qsp" is the number of times that the RCU was waiting for a
+       quiescent state from this CPU.
+
+o      "cbr" is the number of times that this CPU had RCU callbacks
+       that had passed through a grace period, and were thus ready
+       to be invoked.
+
+o      "cng" is the number of times that this CPU needed another
+       grace period while RCU was idle.
+
+o      "gpc" is the number of times that an old grace period had
+       completed, but this CPU was not yet aware of it.
+
+o      "gps" is the number of times that a new grace period had started,
+       but this CPU was not yet aware of it.
+
+o      "nf" is the number of times that this CPU suspected that the
+       current grace period had run for too long, and thus needed to
+       be forced.
+
+       Please note that "forcing" consists of sending resched IPIs
+       to holdout CPUs.  If that CPU really still is in an old RCU
+       read-side critical section, then we really do have to wait for it.
+       The assumption behing "forcing" is that the CPU is not still in
+       an old RCU read-side critical section, but has not yet responded
+       for some other reason.
+
+o      "nn" is the number of times that this CPU needed nothing.  Alert
+       readers will note that the rcu "nn" number for a given CPU very
+       closely matches the rcu_bh "np" number for that same CPU.  This
+       is due to short-circuit evaluation in rcu_pending().
index 629c92e99783ecb7934ee00cf42c4a9f8556004f..34614b4c708eba850acad3ac15f7e59add026f3e 100644 (file)
@@ -184,8 +184,9 @@ length. Single character labels using special characters, that being anything
 other than a letter or digit, are reserved for use by the Smack development
 team. Smack labels are unstructured, case sensitive, and the only operation
 ever performed on them is comparison for equality. Smack labels cannot
-contain unprintable characters or the "/" (slash) character. Smack labels
-cannot begin with a '-', which is reserved for special options.
+contain unprintable characters, the "/" (slash), the "\" (backslash), the "'"
+(quote) and '"' (double-quote) characters.
+Smack labels cannot begin with a '-', which is reserved for special options.
 
 There are some predefined labels:
 
@@ -523,3 +524,18 @@ Smack supports some mount options:
 
 These mount options apply to all file system types.
 
+Smack auditing
+
+If you want Smack auditing of security events, you need to set CONFIG_AUDIT
+in your kernel configuration.
+By default, all denied events will be audited. You can change this behavior by
+writing a single character to the /smack/logging file :
+0 : no logging
+1 : log denied (default)
+2 : log accepted
+3 : log denied & accepted
+
+Events are logged as 'key=value' pairs, for each event you at least will get
+the subjet, the object, the rights requested, the action, the kernel function
+that triggered the event, plus other pairs depending on the type of event
+audited.
index 6fab97ea7e6b0ecd4b3973cd0787257f14647617..8d2158a1c6aaf433e8063650309be1667954f062 100644 (file)
@@ -186,7 +186,7 @@ a virtual address mapping (unlike the earlier scheme of virtual address
 do not have a corresponding kernel virtual address space mapping) and
 low-memory pages.
 
-Note: Please refer to Documentation/PCI/PCI-DMA-mapping.txt for a discussion
+Note: Please refer to Documentation/DMA-mapping.txt for a discussion
 on PCI high mem DMA aspects and mapping of scatter gather lists, and support
 for 64 bit PCI.
 
index 4dae9a3840bf9953ed5f12be7aae10625d6a5b99..0494f78d87e40c225eb1dc1a1489acd891210761 100644 (file)
@@ -60,7 +60,7 @@ go_lock          | Called for the first local holder of a lock
 go_unlock        | Called on the final local unlock of a lock
 go_dump          | Called to print content of object for debugfs file, or on
                  | error to dump glock to the log.
-go_type;         | The type of the glock, LM_TYPE_.....
+go_type          | The type of the glock, LM_TYPE_.....
 go_min_hold_time | The minimum hold time
 
 The minimum hold time for each lock is the time after a remote lock
index 593004b6bbabaeee282b1041835f580cf12baa2e..5e3ab8f3beff15f0597368de302f5361fad8b504 100644 (file)
@@ -11,18 +11,15 @@ their I/O so file system consistency is maintained.  One of the nifty
 features of GFS is perfect consistency -- changes made to the file system
 on one machine show up immediately on all other machines in the cluster.
 
-GFS uses interchangable inter-node locking mechanisms.  Different lock
-modules can plug into GFS and each file system selects the appropriate
-lock module at mount time.  Lock modules include:
+GFS uses interchangable inter-node locking mechanisms, the currently
+supported mechanisms are:
 
   lock_nolock -- allows gfs to be used as a local file system
 
   lock_dlm -- uses a distributed lock manager (dlm) for inter-node locking
   The dlm is found at linux/fs/dlm/
 
-In addition to interfacing with an external locking manager, a gfs lock
-module is responsible for interacting with external cluster management
-systems.  Lock_dlm depends on user space cluster management systems found
+Lock_dlm depends on user space cluster management systems found
 at the URL above.
 
 To use gfs as a local file system, no external clustering systems are
@@ -31,13 +28,19 @@ needed, simply:
   $ mkfs -t gfs2 -p lock_nolock -j 1 /dev/block_device
   $ mount -t gfs2 /dev/block_device /dir
 
-GFS2 is not on-disk compatible with previous versions of GFS.
+If you are using Fedora, you need to install the gfs2-utils package
+and, for lock_dlm, you will also need to install the cman package
+and write a cluster.conf as per the documentation.
+
+GFS2 is not on-disk compatible with previous versions of GFS, but it
+is pretty close.
 
 The following man pages can be found at the URL above:
-  gfs2_fsck    to repair a filesystem
+  fsck.gfs2    to repair a filesystem
   gfs2_grow    to expand a filesystem online
   gfs2_jadd    to add journals to a filesystem online
   gfs2_tool    to manipulate, examine and tune a filesystem
   gfs2_quota   to examine and change quota values in a filesystem
+  gfs2_convert to convert a gfs filesystem to gfs2 in-place
   mount.gfs2   to help mount(8) mount a filesystem
   mkfs.gfs2    to make a filesystem
diff --git a/Documentation/futex-requeue-pi.txt b/Documentation/futex-requeue-pi.txt
new file mode 100644 (file)
index 0000000..9dc1ff4
--- /dev/null
@@ -0,0 +1,131 @@
+Futex Requeue PI
+----------------
+
+Requeueing of tasks from a non-PI futex to a PI futex requires
+special handling in order to ensure the underlying rt_mutex is never
+left without an owner if it has waiters; doing so would break the PI
+boosting logic [see rt-mutex-desgin.txt] For the purposes of
+brevity, this action will be referred to as "requeue_pi" throughout
+this document.  Priority inheritance is abbreviated throughout as
+"PI".
+
+Motivation
+----------
+
+Without requeue_pi, the glibc implementation of
+pthread_cond_broadcast() must resort to waking all the tasks waiting
+on a pthread_condvar and letting them try to sort out which task
+gets to run first in classic thundering-herd formation.  An ideal
+implementation would wake the highest-priority waiter, and leave the
+rest to the natural wakeup inherent in unlocking the mutex
+associated with the condvar.
+
+Consider the simplified glibc calls:
+
+/* caller must lock mutex */
+pthread_cond_wait(cond, mutex)
+{
+       lock(cond->__data.__lock);
+       unlock(mutex);
+       do {
+          unlock(cond->__data.__lock);
+          futex_wait(cond->__data.__futex);
+          lock(cond->__data.__lock);
+       } while(...)
+       unlock(cond->__data.__lock);
+       lock(mutex);
+}
+
+pthread_cond_broadcast(cond)
+{
+       lock(cond->__data.__lock);
+       unlock(cond->__data.__lock);
+       futex_requeue(cond->data.__futex, cond->mutex);
+}
+
+Once pthread_cond_broadcast() requeues the tasks, the cond->mutex
+has waiters. Note that pthread_cond_wait() attempts to lock the
+mutex only after it has returned to user space.  This will leave the
+underlying rt_mutex with waiters, and no owner, breaking the
+previously mentioned PI-boosting algorithms.
+
+In order to support PI-aware pthread_condvar's, the kernel needs to
+be able to requeue tasks to PI futexes.  This support implies that
+upon a successful futex_wait system call, the caller would return to
+user space already holding the PI futex.  The glibc implementation
+would be modified as follows:
+
+
+/* caller must lock mutex */
+pthread_cond_wait_pi(cond, mutex)
+{
+       lock(cond->__data.__lock);
+       unlock(mutex);
+       do {
+          unlock(cond->__data.__lock);
+          futex_wait_requeue_pi(cond->__data.__futex);
+          lock(cond->__data.__lock);
+       } while(...)
+       unlock(cond->__data.__lock);
+        /* the kernel acquired the the mutex for us */
+}
+
+pthread_cond_broadcast_pi(cond)
+{
+       lock(cond->__data.__lock);
+       unlock(cond->__data.__lock);
+       futex_requeue_pi(cond->data.__futex, cond->mutex);
+}
+
+The actual glibc implementation will likely test for PI and make the
+necessary changes inside the existing calls rather than creating new
+calls for the PI cases.  Similar changes are needed for
+pthread_cond_timedwait() and pthread_cond_signal().
+
+Implementation
+--------------
+
+In order to ensure the rt_mutex has an owner if it has waiters, it
+is necessary for both the requeue code, as well as the waiting code,
+to be able to acquire the rt_mutex before returning to user space.
+The requeue code cannot simply wake the waiter and leave it to
+acquire the rt_mutex as it would open a race window between the
+requeue call returning to user space and the waiter waking and
+starting to run.  This is especially true in the uncontended case.
+
+The solution involves two new rt_mutex helper routines,
+rt_mutex_start_proxy_lock() and rt_mutex_finish_proxy_lock(), which
+allow the requeue code to acquire an uncontended rt_mutex on behalf
+of the waiter and to enqueue the waiter on a contended rt_mutex.
+Two new system calls provide the kernel<->user interface to
+requeue_pi: FUTEX_WAIT_REQUEUE_PI and FUTEX_REQUEUE_CMP_PI.
+
+FUTEX_WAIT_REQUEUE_PI is called by the waiter (pthread_cond_wait()
+and pthread_cond_timedwait()) to block on the initial futex and wait
+to be requeued to a PI-aware futex.  The implementation is the
+result of a high-speed collision between futex_wait() and
+futex_lock_pi(), with some extra logic to check for the additional
+wake-up scenarios.
+
+FUTEX_REQUEUE_CMP_PI is called by the waker
+(pthread_cond_broadcast() and pthread_cond_signal()) to requeue and
+possibly wake the waiting tasks. Internally, this system call is
+still handled by futex_requeue (by passing requeue_pi=1).  Before
+requeueing, futex_requeue() attempts to acquire the requeue target
+PI futex on behalf of the top waiter.  If it can, this waiter is
+woken.  futex_requeue() then proceeds to requeue the remaining
+nr_wake+nr_requeue tasks to the PI futex, calling
+rt_mutex_start_proxy_lock() prior to each requeue to prepare the
+task as a waiter on the underlying rt_mutex.  It is possible that
+the lock can be acquired at this stage as well, if so, the next
+waiter is woken to finish the acquisition of the lock.
+
+FUTEX_REQUEUE_PI accepts nr_wake and nr_requeue as arguments, but
+their sum is all that really matters.  futex_requeue() will wake or
+requeue up to nr_wake + nr_requeue tasks.  It will wake only as many
+tasks as it can acquire the lock for, which in the majority of cases
+should be 0 as good programming practice dictates that the caller of
+either pthread_cond_broadcast() or pthread_cond_signal() acquire the
+mutex prior to making the call. FUTEX_REQUEUE_PI requires that
+nr_wake=1.  nr_requeue should be INT_MAX for broadcast and 0 for
+signal.
index fd5cac013037defc68c3ef118ed70b476debee71..72d3bf08d79b769ec909ed8d37977bea41b6679f 100644 (file)
@@ -56,7 +56,6 @@ parameter is applicable:
        ISAPNP  ISA PnP code is enabled.
        ISDN    Appropriate ISDN support is enabled.
        JOY     Appropriate joystick support is enabled.
-       KMEMTRACE kmemtrace is enabled.
        LIBATA  Libata driver is enabled
        LP      Printer support is enabled.
        LOOP    Loopback device support is enabled.
@@ -329,11 +328,6 @@ and is between 256 and 4096 characters. It is defined in the file
                                    flushed before they will be reused, which
                                    is a lot of faster
 
-       amd_iommu_size= [HW,X86-64]
-                       Define the size of the aperture for the AMD IOMMU
-                       driver. Possible values are:
-                       '32M', '64M' (default), '128M', '256M', '512M', '1G'
-
        amijoy.map=     [HW,JOY] Amiga joystick support
                        Map of devices attached to JOY0DAT and JOY1DAT
                        Format: <a>,<b>
@@ -646,6 +640,13 @@ and is between 256 and 4096 characters. It is defined in the file
                        DMA-API debugging code disables itself because the
                        architectural default is too low.
 
+       dma_debug_driver=<driver_name>
+                       With this option the DMA-API debugging driver
+                       filter feature can be enabled at boot time. Just
+                       pass the driver to filter for as the parameter.
+                       The filter can be disabled or changed to another
+                       driver later using sysfs.
+
        dscc4.setup=    [NET]
 
        dtc3181e=       [HW,SCSI]
@@ -752,12 +753,25 @@ and is between 256 and 4096 characters. It is defined in the file
                        ia64_pal_cache_flush instead of SAL_CACHE_FLUSH.
 
        ftrace=[tracer]
-                       [ftrace] will set and start the specified tracer
+                       [FTRACE] will set and start the specified tracer
                        as early as possible in order to facilitate early
                        boot debugging.
 
        ftrace_dump_on_oops
-                       [ftrace] will dump the trace buffers on oops.
+                       [FTRACE] will dump the trace buffers on oops.
+
+       ftrace_filter=[function-list]
+                       [FTRACE] Limit the functions traced by the function
+                       tracer at boot up. function-list is a comma separated
+                       list of functions. This list can be changed at run
+                       time by the set_ftrace_filter file in the debugfs
+                       tracing directory. 
+
+       ftrace_notrace=[function-list]
+                       [FTRACE] Do not trace the functions specified in
+                       function-list. This list can be changed at run time
+                       by the set_ftrace_notrace file in the debugfs
+                       tracing directory.
 
        gamecon.map[2|3]=
                        [HW,JOY] Multisystem joystick and NES/SNES/PSX pad
@@ -914,6 +928,12 @@ and is between 256 and 4096 characters. It is defined in the file
                        Formt: { "sha1" | "md5" }
                        default: "sha1"
 
+       ima_tcb         [IMA]
+                       Load a policy which meets the needs of the Trusted
+                       Computing Base.  This means IMA will measure all
+                       programs exec'd, files mmap'd for exec, and all files
+                       opened for read by uid=0.
+
        in2000=         [HW,SCSI]
                        See header of drivers/scsi/in2000.c.
 
@@ -1054,15 +1074,6 @@ and is between 256 and 4096 characters. It is defined in the file
                        use the HighMem zone if it exists, and the Normal
                        zone if it does not.
 
-       kmemtrace.enable=       [KNL,KMEMTRACE] Format: { yes | no }
-                               Controls whether kmemtrace is enabled
-                               at boot-time.
-
-       kmemtrace.subbufs=n     [KNL,KMEMTRACE] Overrides the number of
-                       subbufs kmemtrace's relay channel has. Set this
-                       higher than default (KMEMTRACE_N_SUBBUFS in code) if
-                       you experience buffer overruns.
-
        kgdboc=         [HW] kgdb over consoles.
                        Requires a tty driver that supports console polling.
                        (only serial suported for now)
@@ -1575,6 +1586,9 @@ and is between 256 and 4096 characters. It is defined in the file
        noinitrd        [RAM] Tells the kernel not to load any configured
                        initial RAM disk.
 
+       nointremap      [X86-64, Intel-IOMMU] Do not enable interrupt
+                       remapping.
+
        nointroute      [IA-64]
 
        nojitter        [IA64] Disables jitter checking for ITC timers.
@@ -1660,6 +1674,14 @@ and is between 256 and 4096 characters. It is defined in the file
        oprofile.timer= [HW]
                        Use timer interrupt instead of performance counters
 
+       oprofile.cpu_type=      Force an oprofile cpu type
+                       This might be useful if you have an older oprofile
+                       userland or if you want common events.
+                       Format: { archperfmon }
+                       archperfmon: [X86] Force use of architectural
+                               perfmon on Intel CPUs instead of the
+                               CPU specific event set.
+
        osst=           [HW,SCSI] SCSI Tape Driver
                        Format: <buffer_size>,<write_threshold>
                        See also Documentation/scsi/st.txt.
index f5b7127f54acb6af1d9f997a40e099b60c0b7571..7f5809eddee62eaf524103eeda485f5e553d5a01 100644 (file)
@@ -31,6 +31,7 @@ Contents:
 
      - Locking functions.
      - Interrupt disabling functions.
+     - Sleep and wake-up functions.
      - Miscellaneous functions.
 
  (*) Inter-CPU locking barrier effects.
@@ -1217,6 +1218,132 @@ barriers are required in such a situation, they must be provided from some
 other means.
 
 
+SLEEP AND WAKE-UP FUNCTIONS
+---------------------------
+
+Sleeping and waking on an event flagged in global data can be viewed as an
+interaction between two pieces of data: the task state of the task waiting for
+the event and the global data used to indicate the event.  To make sure that
+these appear to happen in the right order, the primitives to begin the process
+of going to sleep, and the primitives to initiate a wake up imply certain
+barriers.
+
+Firstly, the sleeper normally follows something like this sequence of events:
+
+       for (;;) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               if (event_indicated)
+                       break;
+               schedule();
+       }
+
+A general memory barrier is interpolated automatically by set_current_state()
+after it has altered the task state:
+
+       CPU 1
+       ===============================
+       set_current_state();
+         set_mb();
+           STORE current->state
+           <general barrier>
+       LOAD event_indicated
+
+set_current_state() may be wrapped by:
+
+       prepare_to_wait();
+       prepare_to_wait_exclusive();
+
+which therefore also imply a general memory barrier after setting the state.
+The whole sequence above is available in various canned forms, all of which
+interpolate the memory barrier in the right place:
+
+       wait_event();
+       wait_event_interruptible();
+       wait_event_interruptible_exclusive();
+       wait_event_interruptible_timeout();
+       wait_event_killable();
+       wait_event_timeout();
+       wait_on_bit();
+       wait_on_bit_lock();
+
+
+Secondly, code that performs a wake up normally follows something like this:
+
+       event_indicated = 1;
+       wake_up(&event_wait_queue);
+
+or:
+
+       event_indicated = 1;
+       wake_up_process(event_daemon);
+
+A write memory barrier is implied by wake_up() and co. if and only if they wake
+something up.  The barrier occurs before the task state is cleared, and so sits
+between the STORE to indicate the event and the STORE to set TASK_RUNNING:
+
+       CPU 1                           CPU 2
+       =============================== ===============================
+       set_current_state();            STORE event_indicated
+         set_mb();                     wake_up();
+           STORE current->state          <write barrier>
+           <general barrier>             STORE current->state
+       LOAD event_indicated
+
+The available waker functions include:
+
+       complete();
+       wake_up();
+       wake_up_all();
+       wake_up_bit();
+       wake_up_interruptible();
+       wake_up_interruptible_all();
+       wake_up_interruptible_nr();
+       wake_up_interruptible_poll();
+       wake_up_interruptible_sync();
+       wake_up_interruptible_sync_poll();
+       wake_up_locked();
+       wake_up_locked_poll();
+       wake_up_nr();
+       wake_up_poll();
+       wake_up_process();
+
+
+[!] Note that the memory barriers implied by the sleeper and the waker do _not_
+order multiple stores before the wake-up with respect to loads of those stored
+values after the sleeper has called set_current_state().  For instance, if the
+sleeper does:
+
+       set_current_state(TASK_INTERRUPTIBLE);
+       if (event_indicated)
+               break;
+       __set_current_state(TASK_RUNNING);
+       do_something(my_data);
+
+and the waker does:
+
+       my_data = value;
+       event_indicated = 1;
+       wake_up(&event_wait_queue);
+
+there's no guarantee that the change to event_indicated will be perceived by
+the sleeper as coming after the change to my_data.  In such a circumstance, the
+code on both sides must interpolate its own memory barriers between the
+separate data accesses.  Thus the above sleeper ought to do:
+
+       set_current_state(TASK_INTERRUPTIBLE);
+       if (event_indicated) {
+               smp_rmb();
+               do_something(my_data);
+       }
+
+and the waker should do:
+
+       my_data = value;
+       smp_wmb();
+       event_indicated = 1;
+       wake_up(&event_wait_queue);
+
+
 MISCELLANEOUS FUNCTIONS
 -----------------------
 
@@ -1366,7 +1493,7 @@ WHERE ARE MEMORY BARRIERS NEEDED?
 
 Under normal operation, memory operation reordering is generally not going to
 be a problem as a single-threaded linear piece of code will still appear to
-work correctly, even if it's in an SMP kernel.  There are, however, three
+work correctly, even if it's in an SMP kernel.  There are, however, four
 circumstances in which reordering definitely _could_ be a problem:
 
  (*) Interprocessor interaction.
index 5ba4d3fc625a424b341bfa5b5853473eaf80fe6a..1df7f9cdab0576227671703c6fec1fc780ec596b 100644 (file)
@@ -4,6 +4,7 @@
 CONTENTS
 ========
 
+0. WARNING
 1. Overview
   1.1 The problem
   1.2 The solution
@@ -14,6 +15,23 @@ CONTENTS
 3. Future plans
 
 
+0. WARNING
+==========
+
+ Fiddling with these settings can result in an unstable system, the knobs are
+ root only and assumes root knows what he is doing.
+
+Most notable:
+
+ * very small values in sched_rt_period_us can result in an unstable
+   system when the period is smaller than either the available hrtimer
+   resolution, or the time it takes to handle the budget refresh itself.
+
+ * very small values in sched_rt_runtime_us can result in an unstable
+   system when the runtime is so small the system has difficulty making
+   forward progress (NOTE: the migration thread and kstopmachine both
+   are real-time processes).
+
 1. Overview
 ===========
 
@@ -169,7 +187,7 @@ get their allocated time.
 
 Implementing SCHED_EDF might take a while to complete. Priority Inheritance is
 the biggest challenge as the current linux PI infrastructure is geared towards
-the limited static priority levels 0-139. With deadline scheduling you need to
+the limited static priority levels 0-99. With deadline scheduling you need to
 do deadline inheritance (since priority is inversely proportional to the
 deadline delta (deadline - now).
 
index f11ca7979fa67b5bbf08339cf473d110ecf92f7d..322a00bb99d97f703130de7f349f2dbc9b6fa24e 100644 (file)
@@ -32,6 +32,7 @@ show up in /proc/sys/kernel:
 - kstack_depth_to_print       [ X86 only ]
 - l2cr                        [ PPC only ]
 - modprobe                    ==> Documentation/debugging-modules.txt
+- modules_disabled
 - msgmax
 - msgmnb
 - msgmni
@@ -184,6 +185,16 @@ kernel stack.
 
 ==============================================================
 
+modules_disabled:
+
+A toggle value indicating if modules are allowed to be loaded
+in an otherwise modular kernel.  This toggle defaults to off
+(0), but can be set true (1).  Once true, modules can be
+neither loaded nor unloaded, and the toggle cannot be set back
+to false.
+
+==============================================================
+
 osrelease, ostype & version:
 
 # cat osrelease
diff --git a/Documentation/trace/events.txt b/Documentation/trace/events.txt
new file mode 100644 (file)
index 0000000..f157d75
--- /dev/null
@@ -0,0 +1,90 @@
+                            Event Tracing
+
+               Documentation written by Theodore Ts'o
+                       Updated by Li Zefan
+
+1. Introduction
+===============
+
+Tracepoints (see Documentation/trace/tracepoints.txt) can be used
+without creating custom kernel modules to register probe functions
+using the event tracing infrastructure.
+
+Not all tracepoints can be traced using the event tracing system;
+the kernel developer must provide code snippets which define how the
+tracing information is saved into the tracing buffer, and how the
+tracing information should be printed.
+
+2. Using Event Tracing
+======================
+
+2.1 Via the 'set_event' interface
+---------------------------------
+
+The events which are available for tracing can be found in the file
+/debug/tracing/available_events.
+
+To enable a particular event, such as 'sched_wakeup', simply echo it
+to /debug/tracing/set_event. For example:
+
+       # echo sched_wakeup >> /debug/tracing/set_event
+
+[ Note: '>>' is necessary, otherwise it will firstly disable
+  all the events. ]
+
+To disable an event, echo the event name to the set_event file prefixed
+with an exclamation point:
+
+       # echo '!sched_wakeup' >> /debug/tracing/set_event
+
+To disable all events, echo an empty line to the set_event file:
+
+       # echo > /debug/tracing/set_event
+
+To enable all events, echo '*:*' or '*:' to the set_event file:
+
+       # echo *:* > /debug/tracing/set_event
+
+The events are organized into subsystems, such as ext4, irq, sched,
+etc., and a full event name looks like this: <subsystem>:<event>.  The
+subsystem name is optional, but it is displayed in the available_events
+file.  All of the events in a subsystem can be specified via the syntax
+"<subsystem>:*"; for example, to enable all irq events, you can use the
+command:
+
+       # echo 'irq:*' > /debug/tracing/set_event
+
+2.2 Via the 'enable' toggle
+---------------------------
+
+The events available are also listed in /debug/tracing/events/ hierarchy
+of directories.
+
+To enable event 'sched_wakeup':
+
+       # echo 1 > /debug/tracing/events/sched/sched_wakeup/enable
+
+To disable it:
+
+       # echo 0 > /debug/tracing/events/sched/sched_wakeup/enable
+
+To enable all events in sched subsystem:
+
+       # echo 1 > /debug/tracing/events/sched/enable
+
+To eanble all events:
+
+       # echo 1 > /debug/tracing/events/enable
+
+When reading one of these enable files, there are four results:
+
+ 0 - all events this file affects are disabled
+ 1 - all events this file affects are enabled
+ X - there is a mixture of events enabled and disabled
+ ? - this file does not affect any event
+
+3. Defining an event-enabled tracepoint
+=======================================
+
+See The example provided in samples/trace_events
+
index fd9a3e69381351aeeaa6712d07c5170aa7dca1a4..2a82d8602944abca930635cff44f37c52238529d 100644 (file)
@@ -179,7 +179,7 @@ Here is the list of current tracers that may be configured.
 
        Function call tracer to trace all kernel functions.
 
-  "function_graph_tracer"
+  "function_graph"
 
        Similar to the function tracer except that the
        function tracer probes the functions on their entry
@@ -518,9 +518,18 @@ priority with zero (0) being the highest priority and the nice
 values starting at 100 (nice -20). Below is a quick chart to map
 the kernel priority to user land priorities.
 
-  Kernel priority: 0 to 99    ==> user RT priority 99 to 0
-  Kernel priority: 100 to 139 ==> user nice -20 to 19
-  Kernel priority: 140        ==> idle task priority
+   Kernel Space                     User Space
+ ===============================================================
+   0(high) to  98(low)     user RT priority 99(high) to 1(low)
+                           with SCHED_RR or SCHED_FIFO
+ ---------------------------------------------------------------
+  99                       sched_priority is not used in scheduling
+                           decisions(it must be specified as 0)
+ ---------------------------------------------------------------
+ 100(high) to 139(low)     user nice -20(high) to 19(low)
+ ---------------------------------------------------------------
+ 140                       idle task priority
+ ---------------------------------------------------------------
 
 The task states are:
 
diff --git a/Documentation/trace/power.txt b/Documentation/trace/power.txt
new file mode 100644 (file)
index 0000000..cd805e1
--- /dev/null
@@ -0,0 +1,17 @@
+The power tracer collects detailed information about C-state and P-state
+transitions, instead of just looking at the high-level "average"
+information.
+
+There is a helper script found in scrips/tracing/power.pl in the kernel
+sources which can be used to parse this information and create a
+Scalable Vector Graphics (SVG) picture from the trace data.
+
+To use this tracer:
+
+       echo 0 > /sys/kernel/debug/tracing/tracing_enabled
+       echo power > /sys/kernel/debug/tracing/current_tracer
+       echo 1 > /sys/kernel/debug/tracing/tracing_enabled
+       sleep 1
+       echo 0 > /sys/kernel/debug/tracing/tracing_enabled
+       cat /sys/kernel/debug/tracing/trace | \
+               perl scripts/tracing/power.pl > out.sv
index e0203662f9e9f8a1a907060437f3fcdf907e2667..8da3a795083fec448cb7e13831b0c10180ff0b6e 100644 (file)
@@ -50,6 +50,10 @@ Protocol 2.08:       (Kernel 2.6.26) Added crc32 checksum and ELF format
 Protocol 2.09: (Kernel 2.6.26) Added a field of 64-bit physical
                pointer to single linked list of struct setup_data.
 
+Protocol 2.10: (Kernel 2.6.31) Added a protocol for relaxed alignment
+               beyond the kernel_alignment added, new init_size and
+               pref_address fields.  Added extended boot loader IDs.
+
 **** MEMORY LAYOUT
 
 The traditional memory map for the kernel loader, used for Image or
@@ -168,12 +172,13 @@ Offset    Proto   Name            Meaning
 021C/4 2.00+   ramdisk_size    initrd size (set by boot loader)
 0220/4 2.00+   bootsect_kludge DO NOT USE - for bootsect.S use only
 0224/2 2.01+   heap_end_ptr    Free memory after setup end
-0226/2 N/A     pad1            Unused
+0226/1 2.02+(3 ext_loader_ver  Extended boot loader version
+0227/1 2.02+(3 ext_loader_type Extended boot loader ID
 0228/4 2.02+   cmd_line_ptr    32-bit pointer to the kernel command line
 022C/4 2.03+   ramdisk_max     Highest legal initrd address
 0230/4 2.05+   kernel_alignment Physical addr alignment required for kernel
 0234/1 2.05+   relocatable_kernel Whether kernel is relocatable or not
-0235/1 N/A     pad2            Unused
+0235/1 2.10+   min_alignment   Minimum alignment, as a power of two
 0236/2 N/A     pad3            Unused
 0238/4 2.06+   cmdline_size    Maximum size of the kernel command line
 023C/4 2.07+   hardware_subarch Hardware subarchitecture
@@ -182,6 +187,8 @@ Offset      Proto   Name            Meaning
 024C/4 2.08+   payload_length  Length of kernel payload
 0250/8 2.09+   setup_data      64-bit physical pointer to linked list
                                of struct setup_data
+0258/8 2.10+   pref_address    Preferred loading address
+0260/4 2.10+   init_size       Linear memory required during initialization
 
 (1) For backwards compatibility, if the setup_sects field contains 0, the
     real value is 4.
@@ -190,6 +197,8 @@ Offset      Proto   Name            Meaning
     field are unusable, which means the size of a bzImage kernel
     cannot be determined.
 
+(3) Ignored, but safe to set, for boot protocols 2.02-2.09.
+
 If the "HdrS" (0x53726448) magic number is not found at offset 0x202,
 the boot protocol version is "old".  Loading an old kernel, the
 following parameters should be assumed:
@@ -343,18 +352,32 @@ Protocol: 2.00+
   0xTV here, where T is an identifier for the boot loader and V is
   a version number.  Otherwise, enter 0xFF here.
 
+  For boot loader IDs above T = 0xD, write T = 0xE to this field and
+  write the extended ID minus 0x10 to the ext_loader_type field.
+  Similarly, the ext_loader_ver field can be used to provide more than
+  four bits for the bootloader version.
+
+  For example, for T = 0x15, V = 0x234, write:
+
+  type_of_loader  <- 0xE4
+  ext_loader_type <- 0x05
+  ext_loader_ver  <- 0x23
+
   Assigned boot loader ids:
        0  LILO                 (0x00 reserved for pre-2.00 bootloader)
        1  Loadlin
        2  bootsect-loader      (0x20, all other values reserved)
-       3  SYSLINUX
-       4  EtherBoot
+       3  Syslinux
+       4  Etherboot/gPXE
        5  ELILO
        7  GRUB
-       8  U-BOOT
+       8  U-Boot
        9  Xen
        A  Gujin
        B  Qemu
+       C  Arcturus Networks uCbootloader
+       E  Extended             (see ext_loader_type)
+       F  Special              (0xFF = undefined)
 
   Please contact <hpa@zytor.com> if you need a bootloader ID
   value assigned.
@@ -453,6 +476,35 @@ Protocol:  2.01+
   Set this field to the offset (from the beginning of the real-mode
   code) of the end of the setup stack/heap, minus 0x0200.
 
+Field name:    ext_loader_ver
+Type:          write (optional)
+Offset/size:   0x226/1
+Protocol:      2.02+
+
+  This field is used as an extension of the version number in the
+  type_of_loader field.  The total version number is considered to be
+  (type_of_loader & 0x0f) + (ext_loader_ver << 4).
+
+  The use of this field is boot loader specific.  If not written, it
+  is zero.
+
+  Kernels prior to 2.6.31 did not recognize this field, but it is safe
+  to write for protocol version 2.02 or higher.
+
+Field name:    ext_loader_type
+Type:          write (obligatory if (type_of_loader & 0xf0) == 0xe0)
+Offset/size:   0x227/1
+Protocol:      2.02+
+
+  This field is used as an extension of the type number in
+  type_of_loader field.  If the type in type_of_loader is 0xE, then
+  the actual type is (ext_loader_type + 0x10).
+
+  This field is ignored if the type in type_of_loader is not 0xE.
+
+  Kernels prior to 2.6.31 did not recognize this field, but it is safe
+  to write for protocol version 2.02 or higher.
+
 Field name:    cmd_line_ptr
 Type:          write (obligatory)
 Offset/size:   0x228/4
@@ -482,11 +534,19 @@ Protocol: 2.03+
   0x37FFFFFF, you can start your ramdisk at 0x37FE0000.)
 
 Field name:    kernel_alignment
-Type:          read (reloc)
+Type:          read/modify (reloc)
 Offset/size:   0x230/4
-Protocol:      2.05+
+Protocol:      2.05+ (read), 2.10+ (modify)
+
+  Alignment unit required by the kernel (if relocatable_kernel is
+  true.)  A relocatable kernel that is loaded at an alignment
+  incompatible with the value in this field will be realigned during
+  kernel initialization.
 
-  Alignment unit required by the kernel (if relocatable_kernel is true.)
+  Starting with protocol version 2.10, this reflects the kernel
+  alignment preferred for optimal performance; it is possible for the
+  loader to modify this field to permit a lesser alignment.  See the
+  min_alignment and pref_address field below.
 
 Field name:    relocatable_kernel
 Type:          read (reloc)
@@ -498,6 +558,22 @@ Protocol:  2.05+
   After loading, the boot loader must set the code32_start field to
   point to the loaded code, or to a boot loader hook.
 
+Field name:    min_alignment
+Type:          read (reloc)
+Offset/size:   0x235/1
+Protocol:      2.10+
+
+  This field, if nonzero, indicates as a power of two the minimum
+  alignment required, as opposed to preferred, by the kernel to boot.
+  If a boot loader makes use of this field, it should update the
+  kernel_alignment field with the alignment unit desired; typically:
+
+       kernel_alignment = 1 << min_alignment
+
+  There may be a considerable performance cost with an excessively
+  misaligned kernel.  Therefore, a loader should typically try each
+  power-of-two alignment from kernel_alignment down to this alignment.
+
 Field name:    cmdline_size
 Type:          read
 Offset/size:   0x238/4
@@ -582,6 +658,36 @@ Protocol:  2.09+
   sure to consider the case where the linked list already contains
   entries.
 
+Field name:    pref_address
+Type:          read (reloc)
+Offset/size:   0x258/8
+Protocol:      2.10+
+
+  This field, if nonzero, represents a preferred load address for the
+  kernel.  A relocating bootloader should attempt to load at this
+  address if possible.
+
+  A non-relocatable kernel will unconditionally move itself and to run
+  at this address.
+
+Field name:    init_size
+Type:          read
+Offset/size:   0x25c/4
+
+  This field indicates the amount of linear contiguous memory starting
+  at the kernel runtime start address that the kernel needs before it
+  is capable of examining its memory map.  This is not the same thing
+  as the total amount of memory the kernel needs to boot, but it can
+  be used by a relocating boot loader to help select a safe load
+  address for the kernel.
+
+  The kernel runtime start address is determined by the following algorithm:
+
+  if (relocatable_kernel)
+       runtime_start = align_up(load_address, kernel_alignment)
+  else
+       runtime_start = pref_address
+
 
 **** THE IMAGE CHECKSUM
 
index 34c13040a718f6febbccadc1f32bc24f4a060664..2db5893d6c97234ded88dbc8b52daaa8defc3af4 100644 (file)
@@ -150,11 +150,6 @@ NUMA
                Otherwise, the remaining system RAM is allocated to an
                additional node.
 
-  numa=hotadd=percent
-               Only allow hotadd memory to preallocate page structures upto
-               percent of already available memory.
-               numa=hotadd=0 will disable hotadd memory.
-
 ACPI
 
   acpi=off     Don't enable ACPI
index 29b52b14d0b43950fa79f3948b1fbe4789396fbf..d6498e3cd7133c7d88279c26d8618aa5fc3d10ad 100644 (file)
@@ -6,10 +6,11 @@ Virtual memory map with 4 level page tables:
 0000000000000000 - 00007fffffffffff (=47 bits) user space, different per mm
 hole caused by [48:63] sign extension
 ffff800000000000 - ffff80ffffffffff (=40 bits) guard hole
-ffff880000000000 - ffffc0ffffffffff (=57 TB) direct mapping of all phys. memory
-ffffc10000000000 - ffffc1ffffffffff (=40 bits) hole
-ffffc20000000000 - ffffe1ffffffffff (=45 bits) vmalloc/ioremap space
-ffffe20000000000 - ffffe2ffffffffff (=40 bits) virtual memory map (1TB)
+ffff880000000000 - ffffc7ffffffffff (=64 TB) direct mapping of all phys. memory
+ffffc80000000000 - ffffc8ffffffffff (=40 bits) hole
+ffffc90000000000 - ffffe8ffffffffff (=45 bits) vmalloc/ioremap space
+ffffe90000000000 - ffffe9ffffffffff (=40 bits) hole
+ffffea0000000000 - ffffeaffffffffff (=40 bits) virtual memory map (1TB)
 ... unused hole ...
 ffffffff80000000 - ffffffffa0000000 (=512 MB)  kernel text mapping, from phys 0
 ffffffffa0000000 - fffffffffff00000 (=1536 MB) module mapping space
index cf4abddfc8a40dcc161e851c26294480fff3076f..ccdb57524e3ca776d44a23f87c9c2f212b606f5f 100644 (file)
@@ -71,7 +71,7 @@ P: Person
 M: Mail patches to
 L: Mailing list that is relevant to this area
 W: Web-page with status/info
-T: SCM tree type and location.  Type is one of: git, hg, quilt.
+T: SCM tree type and location.  Type is one of: git, hg, quilt, stgit.
 S: Status, one of the following:
 
        Supported:      Someone is actually paid to look after this.
@@ -159,7 +159,8 @@ F:  drivers/net/r8169.c
 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
 L:     linux-serial@vger.kernel.org
 W:     http://serial.sourceforge.net
-S:     Orphan
+M:     alan@lxorguk.ukuu.org.uk
+S:     Odd Fixes
 F:     drivers/serial/8250*
 F:     include/linux/serial_8250.h
 
@@ -1978,6 +1979,16 @@ F:       Documentation/edac.txt
 F:     drivers/edac/edac_*
 F:     include/linux/edac.h
 
+EDAC-AMD64
+P:     Doug Thompson
+M:     dougthompson@xmission.com
+P:     Borislav Petkov
+M:     borislav.petkov@amd.com
+L:     bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
+W:     bluesmoke.sourceforge.net
+S:     Supported
+F:     drivers/edac/amd64_edac*
+
 EDAC-E752X
 P:     Mark Gross
 M:     mark.gross@intel.com
@@ -5629,6 +5640,7 @@ P:        Alan Cox
 M:     alan@lxorguk.ukuu.org.uk
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
+T:     stgit http://zeniv.linux.org.uk/~alan/ttydev/
 
 TULIP NETWORK DRIVERS
 P:     Grant Grundler
index 9c9d1fd4155fc5e736c98d89e68d034cd8f2b9ef..5bd5259324b7c8827adb237facd7bf120edd4ca2 100644 (file)
@@ -176,22 +176,26 @@ cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
        }
 }
 
-static void
+static int
 dp264_set_affinity(unsigned int irq, const struct cpumask *affinity)
 { 
        spin_lock(&dp264_irq_lock);
        cpu_set_irq_affinity(irq, *affinity);
        tsunami_update_irq_hw(cached_irq_mask);
        spin_unlock(&dp264_irq_lock);
+
+       return 0;
 }
 
-static void
+static int
 clipper_set_affinity(unsigned int irq, const struct cpumask *affinity)
 { 
        spin_lock(&dp264_irq_lock);
        cpu_set_irq_affinity(irq - 16, *affinity);
        tsunami_update_irq_hw(cached_irq_mask);
        spin_unlock(&dp264_irq_lock);
+
+       return 0;
 }
 
 static struct hw_interrupt_type dp264_irq_type = {
index 27f840a4ad3d7ec0949ac92a55ef5c7c1a3b9280..8dd239ebdb9e2cc3489c3d128402a9da37033a29 100644 (file)
@@ -157,13 +157,15 @@ titan_cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
 
 }
 
-static void
+static int
 titan_set_irq_affinity(unsigned int irq, const struct cpumask *affinity)
 { 
        spin_lock(&titan_irq_lock);
        titan_cpu_set_irq_affinity(irq - 16, *affinity);
        titan_update_irq_hw(titan_cached_irq_mask);
        spin_unlock(&titan_irq_lock);
+
+       return 0;
 }
 
 static void
index 3e1714c6523f06f4ab0572886edba151f21ffb8c..664c7b8b1ba87d7d5268c661808636a27b4f610c 100644 (file)
@@ -109,7 +109,7 @@ static void gic_unmask_irq(unsigned int irq)
 }
 
 #ifdef CONFIG_SMP
-static void gic_set_cpu(unsigned int irq, const struct cpumask *mask_val)
+static int gic_set_cpu(unsigned int irq, const struct cpumask *mask_val)
 {
        void __iomem *reg = gic_dist_base(irq) + GIC_DIST_TARGET + (gic_irq(irq) & ~3);
        unsigned int shift = (irq % 4) * 8;
@@ -122,6 +122,8 @@ static void gic_set_cpu(unsigned int irq, const struct cpumask *mask_val)
        val |= 1 << (cpu + shift);
        writel(val, reg);
        spin_unlock(&irq_controller_lock);
+
+       return 0;
 }
 #endif
 
index 599217b2e13f94cea800c55653e6497c9d2ff3ad..f9bd17dd8dd71af1fd6d6c05f7c7781b51daea26 100644 (file)
 #define ASMARM_ARCH_UART_H
 
 #define IMXUART_HAVE_RTSCTS (1<<0)
+#define IMXUART_IRDA        (1<<1)
 
 struct imxuart_platform_data {
        int (*init)(struct platform_device *pdev);
        int (*exit)(struct platform_device *pdev);
        unsigned int flags;
+       void (*irda_enable)(int enable);
+       unsigned int irda_inv_rx:1;
+       unsigned int irda_inv_tx:1;
+       unsigned short transceiver_delay;
 };
 
 #endif
index 0abfbaa59871313c5ce3857457c3407f6ca4bafc..40424edae93912067cabd21a8ce7c4c304a91428 100644 (file)
@@ -147,24 +147,40 @@ static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg)
        return ret;
 }
 
+struct omap_msg_tx_data {
+       mbox_msg_t      msg;
+       void            *arg;
+};
+
+static void omap_msg_tx_end_io(struct request *rq, int error)
+{
+       kfree(rq->special);
+       __blk_put_request(rq->q, rq);
+}
+
 int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg)
 {
+       struct omap_msg_tx_data *tx_data;
        struct request *rq;
        struct request_queue *q = mbox->txq->queue;
-       int ret = 0;
+
+       tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC);
+       if (unlikely(!tx_data))
+               return -ENOMEM;
 
        rq = blk_get_request(q, WRITE, GFP_ATOMIC);
        if (unlikely(!rq)) {
-               ret = -ENOMEM;
-               goto fail;
+               kfree(tx_data);
+               return -ENOMEM;
        }
 
-       rq->data = (void *)msg;
-       blk_insert_request(q, rq, 0, arg);
+       tx_data->msg = msg;
+       tx_data->arg = arg;
+       rq->end_io = omap_msg_tx_end_io;
+       blk_insert_request(q, rq, 0, tx_data);
 
        schedule_work(&mbox->txq->work);
- fail:
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(omap_mbox_msg_send);
 
@@ -178,22 +194,28 @@ static void mbox_tx_work(struct work_struct *work)
        struct request_queue *q = mbox->txq->queue;
 
        while (1) {
+               struct omap_msg_tx_data *tx_data;
+
                spin_lock(q->queue_lock);
-               rq = elv_next_request(q);
+               rq = blk_fetch_request(q);
                spin_unlock(q->queue_lock);
 
                if (!rq)
                        break;
 
-               ret = __mbox_msg_send(mbox, (mbox_msg_t) rq->data, rq->special);
+               tx_data = rq->special;
+
+               ret = __mbox_msg_send(mbox, tx_data->msg, tx_data->arg);
                if (ret) {
                        enable_mbox_irq(mbox, IRQ_TX);
+                       spin_lock(q->queue_lock);
+                       blk_requeue_request(q, rq);
+                       spin_unlock(q->queue_lock);
                        return;
                }
 
                spin_lock(q->queue_lock);
-               if (__blk_end_request(rq, 0, 0))
-                       BUG();
+               __blk_end_request_all(rq, 0);
                spin_unlock(q->queue_lock);
        }
 }
@@ -218,16 +240,13 @@ static void mbox_rx_work(struct work_struct *work)
 
        while (1) {
                spin_lock_irqsave(q->queue_lock, flags);
-               rq = elv_next_request(q);
+               rq = blk_fetch_request(q);
                spin_unlock_irqrestore(q->queue_lock, flags);
                if (!rq)
                        break;
 
-               msg = (mbox_msg_t) rq->data;
-
-               if (blk_end_request(rq, 0, 0))
-                       BUG();
-
+               msg = (mbox_msg_t)rq->special;
+               blk_end_request_all(rq, 0);
                mbox->rxq->callback((void *)msg);
        }
 }
@@ -264,7 +283,6 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
                        goto nomem;
 
                msg = mbox_fifo_read(mbox);
-               rq->data = (void *)msg;
 
                if (unlikely(mbox_seq_test(mbox, msg))) {
                        pr_info("mbox: Illegal seq bit!(%08x)\n", msg);
@@ -272,7 +290,7 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
                                mbox->err_notify();
                }
 
-               blk_insert_request(q, rq, 0, NULL);
+               blk_insert_request(q, rq, 0, (void *)msg);
                if (mbox->ops->type == OMAP_MBOX_TYPE1)
                        break;
        }
@@ -329,16 +347,15 @@ omap_mbox_read(struct device *dev, struct device_attribute *attr, char *buf)
 
        while (1) {
                spin_lock_irqsave(q->queue_lock, flags);
-               rq = elv_next_request(q);
+               rq = blk_fetch_request(q);
                spin_unlock_irqrestore(q->queue_lock, flags);
 
                if (!rq)
                        break;
 
-               *p = (mbox_msg_t) rq->data;
+               *p = (mbox_msg_t)rq->special;
 
-               if (blk_end_request(rq, 0, 0))
-                       BUG();
+               blk_end_request_all(rq, 0);
 
                if (unlikely(mbox_seq_test(mbox, *p))) {
                        pr_info("mbox: Illegal seq bit!(%08x) ignored\n", *p);
index df3925cb1c7fbbcab86f8445491d0e77ebf684a9..d70b445f4a8f0fc82922e848ae4f0bbbae6a1fb5 100644 (file)
@@ -325,12 +325,14 @@ static void end_crisv32_irq(unsigned int irq)
 {
 }
 
-void set_affinity_crisv32_irq(unsigned int irq, const struct cpumask *dest)
+int set_affinity_crisv32_irq(unsigned int irq, const struct cpumask *dest)
 {
        unsigned long flags;
        spin_lock_irqsave(&irq_lock, flags);
        irq_allocations[irq - FIRST_IRQ].mask = *dest;
        spin_unlock_irqrestore(&irq_lock, flags);
+
+       return 0;
 }
 
 static struct irq_chip crisv32_irq_type = {
index 9d1552a9ee2c88ddb40bc7d70dea316f725d2843..8a5bd7a9c6f533b452b21de81127c476b1826765 100644 (file)
@@ -6,6 +6,7 @@ config FRV
        bool
        default y
        select HAVE_IDE
+       select HAVE_ARCH_TRACEHOOK
 
 config ZONE_DMA
        bool
index 287f6f697ce276d55b498cea168a67e402e6b5bf..50ae91b29674584743e5935aa49e0717fb260b34 100644 (file)
@@ -112,7 +112,7 @@ extern unsigned long atomic_test_and_XOR_mask(unsigned long mask, volatile unsig
 #define atomic_clear_mask(mask, v)     atomic_test_and_ANDNOT_mask((mask), (v))
 #define atomic_set_mask(mask, v)       atomic_test_and_OR_mask((mask), (v))
 
-static inline int test_and_clear_bit(int nr, volatile void *addr)
+static inline int test_and_clear_bit(unsigned long nr, volatile void *addr)
 {
        volatile unsigned long *ptr = addr;
        unsigned long mask = 1UL << (nr & 31);
@@ -120,7 +120,7 @@ static inline int test_and_clear_bit(int nr, volatile void *addr)
        return (atomic_test_and_ANDNOT_mask(mask, ptr) & mask) != 0;
 }
 
-static inline int test_and_set_bit(int nr, volatile void *addr)
+static inline int test_and_set_bit(unsigned long nr, volatile void *addr)
 {
        volatile unsigned long *ptr = addr;
        unsigned long mask = 1UL << (nr & 31);
@@ -128,7 +128,7 @@ static inline int test_and_set_bit(int nr, volatile void *addr)
        return (atomic_test_and_OR_mask(mask, ptr) & mask) != 0;
 }
 
-static inline int test_and_change_bit(int nr, volatile void *addr)
+static inline int test_and_change_bit(unsigned long nr, volatile void *addr)
 {
        volatile unsigned long *ptr = addr;
        unsigned long mask = 1UL << (nr & 31);
@@ -136,22 +136,22 @@ static inline int test_and_change_bit(int nr, volatile void *addr)
        return (atomic_test_and_XOR_mask(mask, ptr) & mask) != 0;
 }
 
-static inline void clear_bit(int nr, volatile void *addr)
+static inline void clear_bit(unsigned long nr, volatile void *addr)
 {
        test_and_clear_bit(nr, addr);
 }
 
-static inline void set_bit(int nr, volatile void *addr)
+static inline void set_bit(unsigned long nr, volatile void *addr)
 {
        test_and_set_bit(nr, addr);
 }
 
-static inline void change_bit(int nr, volatile void * addr)
+static inline void change_bit(unsigned long nr, volatile void *addr)
 {
        test_and_change_bit(nr, addr);
 }
 
-static inline void __clear_bit(int nr, volatile void * addr)
+static inline void __clear_bit(unsigned long nr, volatile void *addr)
 {
        volatile unsigned long *a = addr;
        int mask;
@@ -161,7 +161,7 @@ static inline void __clear_bit(int nr, volatile void * addr)
        *a &= ~mask;
 }
 
-static inline void __set_bit(int nr, volatile void * addr)
+static inline void __set_bit(unsigned long nr, volatile void *addr)
 {
        volatile unsigned long *a = addr;
        int mask;
@@ -171,7 +171,7 @@ static inline void __set_bit(int nr, volatile void * addr)
        *a |= mask;
 }
 
-static inline void __change_bit(int nr, volatile void *addr)
+static inline void __change_bit(unsigned long nr, volatile void *addr)
 {
        volatile unsigned long *a = addr;
        int mask;
@@ -181,7 +181,7 @@ static inline void __change_bit(int nr, volatile void *addr)
        *a ^= mask;
 }
 
-static inline int __test_and_clear_bit(int nr, volatile void * addr)
+static inline int __test_and_clear_bit(unsigned long nr, volatile void *addr)
 {
        volatile unsigned long *a = addr;
        int mask, retval;
@@ -193,7 +193,7 @@ static inline int __test_and_clear_bit(int nr, volatile void * addr)
        return retval;
 }
 
-static inline int __test_and_set_bit(int nr, volatile void * addr)
+static inline int __test_and_set_bit(unsigned long nr, volatile void *addr)
 {
        volatile unsigned long *a = addr;
        int mask, retval;
@@ -205,7 +205,7 @@ static inline int __test_and_set_bit(int nr, volatile void * addr)
        return retval;
 }
 
-static inline int __test_and_change_bit(int nr, volatile void * addr)
+static inline int __test_and_change_bit(unsigned long nr, volatile void *addr)
 {
        volatile unsigned long *a = addr;
        int mask, retval;
@@ -220,12 +220,13 @@ static inline int __test_and_change_bit(int nr, volatile void * addr)
 /*
  * This routine doesn't need to be atomic.
  */
-static inline int __constant_test_bit(int nr, const volatile void * addr)
+static inline int
+__constant_test_bit(unsigned long nr, const volatile void *addr)
 {
        return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
 }
 
-static inline int __test_bit(int nr, const volatile void * addr)
+static inline int __test_bit(unsigned long nr, const volatile void *addr)
 {
        int     * a = (int *) addr;
        int     mask;
index 7279ec07d62e32007f91a01bfe58a20014283a4d..7bbf6e47f8c8a5cb216c9b8f5e0b8be3b902c5bb 100644 (file)
@@ -116,6 +116,7 @@ do {                                                                                        \
 } while(0)
 
 #define USE_ELF_CORE_DUMP
+#define CORE_DUMP_USE_REGSET
 #define ELF_FDPIC_CORE_EFLAGS  EF_FRV_FDPIC
 #define ELF_EXEC_PAGESIZE      16384
 
index 585d9b49949a7537d9d1f89221f93c047cfedacf..cc685e60b0f9ce92c06372cd695346a3b3ba6b17 100644 (file)
@@ -87,8 +87,7 @@ static inline void pci_dma_sync_single(struct pci_dev *hwdev,
                                       dma_addr_t dma_handle,
                                       size_t size, int direction)
 {
-       if (direction == PCI_DMA_NONE)
-                BUG();
+       BUG_ON(direction == PCI_DMA_NONE);
 
        frv_cache_wback_inv((unsigned long)bus_to_virt(dma_handle),
                            (unsigned long)bus_to_virt(dma_handle) + size);
@@ -105,9 +104,7 @@ static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
                                   int nelems, int direction)
 {
        int i;
-
-       if (direction == PCI_DMA_NONE)
-                BUG();
+       BUG_ON(direction == PCI_DMA_NONE);
 
        for (i = 0; i < nelems; i++)
                frv_cache_wback_inv(sg_dma_address(&sg[i]),
index cf6934012b64dc70736e26073470e143b2ed11ab..a54b535c9e493f2ba18fa0974993d5859e18bf0a 100644 (file)
@@ -65,6 +65,8 @@
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
+struct task_struct;
+
 /*
  * we dedicate GR28 to keeping a pointer to the current exception frame
  * - gr28 is destroyed on entry to the kernel from userspace
@@ -73,11 +75,18 @@ register struct pt_regs *__frame asm("gr28");
 
 #define user_mode(regs)                        (!((regs)->psr & PSR_S))
 #define instruction_pointer(regs)      ((regs)->pc)
+#define user_stack_pointer(regs)       ((regs)->sp)
 
 extern unsigned long user_stack(const struct pt_regs *);
 extern void show_regs(struct pt_regs *);
 #define profile_pc(regs) ((regs)->pc)
-#endif
+
+#define task_pt_regs(task) ((task)->thread.frame0)
+
+#define arch_has_single_step() (1)
+extern void user_enable_single_step(struct task_struct *);
+extern void user_disable_single_step(struct task_struct *);
 
 #endif /* !__ASSEMBLY__ */
+#endif /* __KERNEL__ */
 #endif /* _ASM_PTRACE_H */
diff --git a/arch/frv/include/asm/syscall.h b/arch/frv/include/asm/syscall.h
new file mode 100644 (file)
index 0000000..70689eb
--- /dev/null
@@ -0,0 +1,123 @@
+/* syscall parameter access functions
+ *
+ * Copyright (C) 2009 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 _ASM_SYSCALL_H
+#define _ASM_SYSCALL_H
+
+#include <linux/err.h>
+#include <asm/ptrace.h>
+
+/*
+ * Get the system call number or -1
+ */
+static inline long syscall_get_nr(struct task_struct *task,
+                                 struct pt_regs *regs)
+{
+       return regs->syscallno;
+}
+
+/*
+ * Restore the clobbered GR8 register
+ * (1st syscall arg was overwritten with syscall return or error)
+ */
+static inline void syscall_rollback(struct task_struct *task,
+                                   struct pt_regs *regs)
+{
+       regs->gr8 = regs->orig_gr8;
+}
+
+/*
+ * See if the syscall return value is an error, returning it if it is and 0 if
+ * not
+ */
+static inline long syscall_get_error(struct task_struct *task,
+                                    struct pt_regs *regs)
+{
+       return IS_ERR_VALUE(regs->gr8) ? regs->gr8 : 0;
+}
+
+/*
+ * Get the syscall return value
+ */
+static inline long syscall_get_return_value(struct task_struct *task,
+                                           struct pt_regs *regs)
+{
+       return regs->gr8;
+}
+
+/*
+ * Set the syscall return value
+ */
+static inline void syscall_set_return_value(struct task_struct *task,
+                                           struct pt_regs *regs,
+                                           int error, long val)
+{
+       if (error)
+               regs->gr8 = -error;
+       else
+               regs->gr8 = val;
+}
+
+/*
+ * Retrieve the system call arguments
+ */
+static inline void syscall_get_arguments(struct task_struct *task,
+                                        struct pt_regs *regs,
+                                        unsigned int i, unsigned int n,
+                                        unsigned long *args)
+{
+       /*
+        * Do this simply for now. If we need to start supporting
+        * fetching arguments from arbitrary indices, this will need some
+        * extra logic. Presently there are no in-tree users that depend
+        * on this behaviour.
+        */
+       BUG_ON(i);
+
+       /* Argument pattern is: GR8, GR9, GR10, GR11, GR12, GR13 */
+       switch (n) {
+       case 6: args[5] = regs->gr13;
+       case 5: args[4] = regs->gr12;
+       case 4: args[3] = regs->gr11;
+       case 3: args[2] = regs->gr10;
+       case 2: args[1] = regs->gr9;
+       case 1: args[0] = regs->gr8;
+               break;
+       default:
+               BUG();
+       }
+}
+
+/*
+ * Alter the system call arguments
+ */
+static inline void syscall_set_arguments(struct task_struct *task,
+                                        struct pt_regs *regs,
+                                        unsigned int i, unsigned int n,
+                                        const unsigned long *args)
+{
+       /* Same note as above applies */
+       BUG_ON(i);
+
+       switch (n) {
+       case 6: regs->gr13 = args[5];
+       case 5: regs->gr12 = args[4];
+       case 4: regs->gr11 = args[3];
+       case 3: regs->gr10 = args[2];
+       case 2: regs->gr9  = args[1];
+       case 1: regs->gr8  = args[0];
+               break;
+       default:
+               BUG();
+       }
+}
+
+#endif /* _ASM_SYSCALL_H */
index bb53ab753ffbf7b3a62e9e105583b4339d9768ce..e8a5ed7be0212791674996fd16afeb4f38a6b751 100644 (file)
@@ -109,20 +109,20 @@ register struct thread_info *__current_thread_info asm("gr15");
  * - other flags in MSW
  */
 #define TIF_SYSCALL_TRACE      0       /* syscall trace active */
-#define TIF_SIGPENDING         1       /* signal pending */
-#define TIF_NEED_RESCHED       2       /* rescheduling necessary */
-#define TIF_SINGLESTEP         3       /* restore singlestep on return to user mode */
-#define TIF_IRET               4       /* return with iret */
+#define TIF_NOTIFY_RESUME      1       /* callback before returning to user */
+#define TIF_SIGPENDING         2       /* signal pending */
+#define TIF_NEED_RESCHED       3       /* rescheduling necessary */
+#define TIF_SINGLESTEP         4       /* restore singlestep on return to user mode */
 #define TIF_RESTORE_SIGMASK    5       /* restore signal mask in do_signal() */
 #define TIF_POLLING_NRFLAG     16      /* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE             17      /* OOM killer killed process */
 #define TIF_FREEZE             18      /* freezing for suspend */
 
 #define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP                (1 << TIF_SINGLESTEP)
-#define _TIF_IRET              (1 << TIF_IRET)
 #define _TIF_RESTORE_SIGMASK   (1 << TIF_RESTORE_SIGMASK)
 #define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)
 #define _TIF_FREEZE            (1 << TIF_FREEZE)
index 1da523b3298e03a36c8e27e23bf9d20f10615e67..356e0e327a8923f87d366776f06e5b916852bf56 100644 (file)
@@ -886,7 +886,6 @@ system_call:
        bnc             icc0,#0,__syscall_badsys
 
        ldi             @(gr15,#TI_FLAGS),gr4
-       ori             gr4,#_TIF_SYSCALL_TRACE,gr4
        andicc          gr4,#_TIF_SYSCALL_TRACE,gr0,icc0
        bne             icc0,#0,__syscall_trace_entry
 
@@ -1150,11 +1149,10 @@ __entry_work_notifysig:
        # perform syscall entry tracing
 __syscall_trace_entry:
        LEDS            0x6320
-       setlos.p        #0,gr8
-       call            do_syscall_trace
+       call            syscall_trace_entry
 
-       ldi             @(gr28,#REG_SYSCALLNO),gr7
-       lddi            @(gr28,#REG_GR(8)) ,gr8
+       lddi.p          @(gr28,#REG_GR(8)) ,gr8
+       ori             gr8,#0,gr7              ; syscall_trace_entry() returned new syscallno
        lddi            @(gr28,#REG_GR(10)),gr10
        lddi.p          @(gr28,#REG_GR(12)),gr12
 
@@ -1169,11 +1167,10 @@ __syscall_exit_work:
        beq             icc0,#1,__entry_work_pending
 
        movsg           psr,gr23
-       andi            gr23,#~PSR_PIL,gr23     ; could let do_syscall_trace() call schedule()
+       andi            gr23,#~PSR_PIL,gr23     ; could let syscall_trace_exit() call schedule()
        movgs           gr23,psr
 
-       setlos.p        #1,gr8
-       call            do_syscall_trace
+       call            syscall_trace_exit
        bra             __entry_resume_userspace
 
 __syscall_badsys:
index 5e7d401d21e7d6455883f118213a040e97754fbf..60eeed3694c0764d2d0b9d7d3a0c2cffe14b9a89 100644 (file)
@@ -19,6 +19,9 @@
 #include <linux/user.h>
 #include <linux/security.h>
 #include <linux/signal.h>
+#include <linux/regset.h>
+#include <linux/elf.h>
+#include <linux/tracehook.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
  * in exit.c or in signal.c.
  */
 
+/*
+ * retrieve the contents of FRV userspace general registers
+ */
+static int genregs_get(struct task_struct *target,
+                      const struct user_regset *regset,
+                      unsigned int pos, unsigned int count,
+                      void *kbuf, void __user *ubuf)
+{
+       const struct user_int_regs *iregs = &target->thread.user->i;
+       int ret;
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 iregs, 0, sizeof(*iregs));
+       if (ret < 0)
+               return ret;
+
+       return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+                                       sizeof(*iregs), -1);
+}
+
+/*
+ * update the contents of the FRV userspace general registers
+ */
+static int genregs_set(struct task_struct *target,
+                      const struct user_regset *regset,
+                      unsigned int pos, unsigned int count,
+                      const void *kbuf, const void __user *ubuf)
+{
+       struct user_int_regs *iregs = &target->thread.user->i;
+       unsigned int offs_gr0, offs_gr1;
+       int ret;
+
+       /* not allowed to set PSR or __status */
+       if (pos < offsetof(struct user_int_regs, psr) + sizeof(long) &&
+           pos + count > offsetof(struct user_int_regs, psr))
+               return -EIO;
+
+       if (pos < offsetof(struct user_int_regs, __status) + sizeof(long) &&
+           pos + count > offsetof(struct user_int_regs, __status))
+               return -EIO;
+
+       /* set the control regs */
+       offs_gr0 = offsetof(struct user_int_regs, gr[0]);
+       offs_gr1 = offsetof(struct user_int_regs, gr[1]);
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                iregs, 0, offs_gr0);
+       if (ret < 0)
+               return ret;
+
+       /* skip GR0/TBR */
+       ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+                                       offs_gr0, offs_gr1);
+       if (ret < 0)
+               return ret;
+
+       /* set the general regs */
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &iregs->gr[1], offs_gr1, sizeof(*iregs));
+       if (ret < 0)
+               return ret;
+
+       return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+                                       sizeof(*iregs), -1);
+}
+
+/*
+ * retrieve the contents of FRV userspace FP/Media registers
+ */
+static int fpmregs_get(struct task_struct *target,
+                      const struct user_regset *regset,
+                      unsigned int pos, unsigned int count,
+                      void *kbuf, void __user *ubuf)
+{
+       const struct user_fpmedia_regs *fpregs = &target->thread.user->f;
+       int ret;
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 fpregs, 0, sizeof(*fpregs));
+       if (ret < 0)
+               return ret;
+
+       return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+                                       sizeof(*fpregs), -1);
+}
+
+/*
+ * update the contents of the FRV userspace FP/Media registers
+ */
+static int fpmregs_set(struct task_struct *target,
+                      const struct user_regset *regset,
+                      unsigned int pos, unsigned int count,
+                      const void *kbuf, const void __user *ubuf)
+{
+       struct user_fpmedia_regs *fpregs = &target->thread.user->f;
+       int ret;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                fpregs, 0, sizeof(*fpregs));
+       if (ret < 0)
+               return ret;
+
+       return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+                                       sizeof(*fpregs), -1);
+}
+
+/*
+ * determine if the FP/Media registers have actually been used
+ */
+static int fpmregs_active(struct task_struct *target,
+                         const struct user_regset *regset)
+{
+       return tsk_used_math(target) ? regset->n : 0;
+}
+
+/*
+ * Define the register sets available on the FRV under Linux
+ */
+enum frv_regset {
+       REGSET_GENERAL,
+       REGSET_FPMEDIA,
+};
+
+static const struct user_regset frv_regsets[] = {
+       /*
+        * General register format is:
+        *      PSR, ISR, CCR, CCCR, LR, LCR, PC, (STATUS), SYSCALLNO, ORIG_G8
+        *      GNER0-1, IACC0, TBR, GR1-63
+        */
+       [REGSET_GENERAL] = {
+               .core_note_type = NT_PRSTATUS,
+               .n              = ELF_NGREG,
+               .size           = sizeof(long),
+               .align          = sizeof(long),
+               .get            = genregs_get,
+               .set            = genregs_set,
+       },
+       /*
+        * FPU/Media register format is:
+        *      FR0-63, FNER0-1, MSR0-1, ACC0-7, ACCG0-8, FSR
+        */
+       [REGSET_FPMEDIA] = {
+               .core_note_type = NT_PRFPREG,
+               .n              = sizeof(struct user_fpmedia_regs) / sizeof(long),
+               .size           = sizeof(long),
+               .align          = sizeof(long),
+               .get            = fpmregs_get,
+               .set            = fpmregs_set,
+               .active         = fpmregs_active,
+       },
+};
+
+static const struct user_regset_view user_frv_native_view = {
+       .name           = "frv",
+       .e_machine      = EM_FRV,
+       .regsets        = frv_regsets,
+       .n              = ARRAY_SIZE(frv_regsets),
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+       return &user_frv_native_view;
+}
+
 /*
  * Get contents of register REGNO in task TASK.
  */
@@ -68,41 +234,24 @@ static inline int put_reg(struct task_struct *task, int regno,
        }
 }
 
-/*
- * check that an address falls within the bounds of the target process's memory
- * mappings
- */
-static inline int is_user_addr_valid(struct task_struct *child,
-                                    unsigned long start, unsigned long len)
-{
-#ifdef CONFIG_MMU
-       if (start >= PAGE_OFFSET || len > PAGE_OFFSET - start)
-               return -EIO;
-       return 0;
-#else
-       struct vm_area_struct *vma;
-
-       vma = find_vma(child->mm, start);
-       if (vma && start >= vma->vm_start && start + len <= vma->vm_end)
-               return 0;
-
-       return -EIO;
-#endif
-}
-
 /*
  * Called by kernel/ptrace.c when detaching..
  *
  * Control h/w single stepping
  */
-void ptrace_disable(struct task_struct *child)
+void user_enable_single_step(struct task_struct *child)
+{
+       child->thread.frame0->__status |= REG__STATUS_STEP;
+}
+
+void user_disable_single_step(struct task_struct *child)
 {
        child->thread.frame0->__status &= ~REG__STATUS_STEP;
 }
 
-void ptrace_enable(struct task_struct *child)
+void ptrace_disable(struct task_struct *child)
 {
-       child->thread.frame0->__status |= REG__STATUS_STEP;
+       user_disable_single_step(child);
 }
 
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
@@ -111,15 +260,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        int ret;
 
        switch (request) {
-               /* when I and D space are separate, these will need to be fixed. */
-       case PTRACE_PEEKTEXT: /* read word at location addr. */
-       case PTRACE_PEEKDATA:
-               ret = -EIO;
-               if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
-                       break;
-               ret = generic_ptrace_peekdata(child, addr, data);
-               break;
-
                /* read the word at location addr in the USER area. */
        case PTRACE_PEEKUSR: {
                tmp = 0;
@@ -163,15 +303,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                break;
        }
 
-               /* when I and D space are separate, this will have to be fixed. */
-       case PTRACE_POKETEXT: /* write the word at location addr. */
-       case PTRACE_POKEDATA:
-               ret = -EIO;
-               if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
-                       break;
-               ret = generic_ptrace_pokedata(child, addr, data);
-               break;
-
        case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
                ret = -EIO;
                if ((addr & 3) || addr < 0)
@@ -179,7 +310,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 
                ret = 0;
                switch (addr >> 2) {
-               case 0 ... PT__END-1:
+               case 0 ... PT__END - 1:
                        ret = put_reg(child, addr >> 2, data);
                        break;
 
@@ -189,95 +320,29 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                }
                break;
 
-       case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
-       case PTRACE_CONT: /* restart after signal. */
-               ret = -EIO;
-               if (!valid_signal(data))
-                       break;
-               if (request == PTRACE_SYSCALL)
-                       set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               else
-                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               child->exit_code = data;
-               ptrace_disable(child);
-               wake_up_process(child);
-               ret = 0;
-               break;
-
-               /* make the child exit.  Best I can do is send it a sigkill.
-                * perhaps it should be put in the status that it wants to
-                * exit.
-                */
-       case PTRACE_KILL:
-               ret = 0;
-               if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
-                       break;
-               child->exit_code = SIGKILL;
-               clear_tsk_thread_flag(child, TIF_SINGLESTEP);
-               ptrace_disable(child);
-               wake_up_process(child);
-               break;
-
-       case PTRACE_SINGLESTEP:  /* set the trap flag. */
-               ret = -EIO;
-               if (!valid_signal(data))
-                       break;
-               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               ptrace_enable(child);
-               child->exit_code = data;
-               wake_up_process(child);
-               ret = 0;
-               break;
-
-       case PTRACE_DETACH:     /* detach a process that was attached. */
-               ret = ptrace_detach(child, data);
-               break;
-
-       case PTRACE_GETREGS: { /* Get all integer regs from the child. */
-               int i;
-               for (i = 0; i < PT__GPEND; i++) {
-                       tmp = get_reg(child, i);
-                       if (put_user(tmp, (unsigned long *) data)) {
-                               ret = -EFAULT;
-                               break;
-                       }
-                       data += sizeof(long);
-               }
-               ret = 0;
-               break;
-       }
-
-       case PTRACE_SETREGS: { /* Set all integer regs in the child. */
-               int i;
-               for (i = 0; i < PT__GPEND; i++) {
-                       if (get_user(tmp, (unsigned long *) data)) {
-                               ret = -EFAULT;
-                               break;
-                       }
-                       put_reg(child, i, tmp);
-                       data += sizeof(long);
-               }
-               ret = 0;
-               break;
-       }
-
-       case PTRACE_GETFPREGS: { /* Get the child FP/Media state. */
-               ret = 0;
-               if (copy_to_user((void *) data,
-                                &child->thread.user->f,
-                                sizeof(child->thread.user->f)))
-                       ret = -EFAULT;
-               break;
-       }
-
-       case PTRACE_SETFPREGS: { /* Set the child FP/Media state. */
-               ret = 0;
-               if (copy_from_user(&child->thread.user->f,
-                                  (void *) data,
-                                  sizeof(child->thread.user->f)))
-                       ret = -EFAULT;
-               break;
-       }
+       case PTRACE_GETREGS:    /* Get all integer regs from the child. */
+               return copy_regset_to_user(child, &user_frv_native_view,
+                                          REGSET_GENERAL,
+                                          0, sizeof(child->thread.user->i),
+                                          (void __user *)data);
+
+       case PTRACE_SETREGS:    /* Set all integer regs in the child. */
+               return copy_regset_from_user(child, &user_frv_native_view,
+                                            REGSET_GENERAL,
+                                            0, sizeof(child->thread.user->i),
+                                            (const void __user *)data);
+
+       case PTRACE_GETFPREGS:  /* Get the child FP/Media state. */
+               return copy_regset_to_user(child, &user_frv_native_view,
+                                          REGSET_FPMEDIA,
+                                          0, sizeof(child->thread.user->f),
+                                          (void __user *)data);
+
+       case PTRACE_SETFPREGS:  /* Set the child FP/Media state. */
+               return copy_regset_from_user(child, &user_frv_native_view,
+                                            REGSET_FPMEDIA,
+                                            0, sizeof(child->thread.user->f),
+                                            (const void __user *)data);
 
        case PTRACE_GETFDPIC:
                tmp = 0;
@@ -300,414 +365,36 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                break;
 
        default:
-               ret = -EIO;
+               ret = ptrace_request(child, request, addr, data);
                break;
        }
        return ret;
 }
 
-int __nongprelbss kstrace;
-
-static const struct {
-       const char      *name;
-       unsigned        argmask;
-} __syscall_name_table[NR_syscalls] = {
-       [0]     = { "restart_syscall"                   },
-       [1]     = { "exit",             0x000001        },
-       [2]     = { "fork",             0xffffff        },
-       [3]     = { "read",             0x000141        },
-       [4]     = { "write",            0x000141        },
-       [5]     = { "open",             0x000235        },
-       [6]     = { "close",            0x000001        },
-       [7]     = { "waitpid",          0x000141        },
-       [8]     = { "creat",            0x000025        },
-       [9]     = { "link",             0x000055        },
-       [10]    = { "unlink",           0x000005        },
-       [11]    = { "execve",           0x000445        },
-       [12]    = { "chdir",            0x000005        },
-       [13]    = { "time",             0x000004        },
-       [14]    = { "mknod",            0x000325        },
-       [15]    = { "chmod",            0x000025        },
-       [16]    = { "lchown",           0x000025        },
-       [17]    = { "break" },
-       [18]    = { "oldstat",          0x000045        },
-       [19]    = { "lseek",            0x000131        },
-       [20]    = { "getpid",           0xffffff        },
-       [21]    = { "mount",            0x043555        },
-       [22]    = { "umount",           0x000005        },
-       [23]    = { "setuid",           0x000001        },
-       [24]    = { "getuid",           0xffffff        },
-       [25]    = { "stime",            0x000004        },
-       [26]    = { "ptrace",           0x004413        },
-       [27]    = { "alarm",            0x000001        },
-       [28]    = { "oldfstat",         0x000041        },
-       [29]    = { "pause",            0xffffff        },
-       [30]    = { "utime",            0x000045        },
-       [31]    = { "stty" },
-       [32]    = { "gtty" },
-       [33]    = { "access",           0x000025        },
-       [34]    = { "nice",             0x000001        },
-       [35]    = { "ftime" },
-       [36]    = { "sync",             0xffffff        },
-       [37]    = { "kill",             0x000011        },
-       [38]    = { "rename",           0x000055        },
-       [39]    = { "mkdir",            0x000025        },
-       [40]    = { "rmdir",            0x000005        },
-       [41]    = { "dup",              0x000001        },
-       [42]    = { "pipe",             0x000004        },
-       [43]    = { "times",            0x000004        },
-       [44]    = { "prof" },
-       [45]    = { "brk",              0x000004        },
-       [46]    = { "setgid",           0x000001        },
-       [47]    = { "getgid",           0xffffff        },
-       [48]    = { "signal",           0x000041        },
-       [49]    = { "geteuid",          0xffffff        },
-       [50]    = { "getegid",          0xffffff        },
-       [51]    = { "acct",             0x000005        },
-       [52]    = { "umount2",          0x000035        },
-       [53]    = { "lock" },
-       [54]    = { "ioctl",            0x000331        },
-       [55]    = { "fcntl",            0x000331        },
-       [56]    = { "mpx" },
-       [57]    = { "setpgid",          0x000011        },
-       [58]    = { "ulimit" },
-       [60]    = { "umask",            0x000002        },
-       [61]    = { "chroot",           0x000005        },
-       [62]    = { "ustat",            0x000043        },
-       [63]    = { "dup2",             0x000011        },
-       [64]    = { "getppid",          0xffffff        },
-       [65]    = { "getpgrp",          0xffffff        },
-       [66]    = { "setsid",           0xffffff        },
-       [67]    = { "sigaction" },
-       [68]    = { "sgetmask" },
-       [69]    = { "ssetmask" },
-       [70]    = { "setreuid" },
-       [71]    = { "setregid" },
-       [72]    = { "sigsuspend" },
-       [73]    = { "sigpending" },
-       [74]    = { "sethostname" },
-       [75]    = { "setrlimit" },
-       [76]    = { "getrlimit" },
-       [77]    = { "getrusage" },
-       [78]    = { "gettimeofday" },
-       [79]    = { "settimeofday" },
-       [80]    = { "getgroups" },
-       [81]    = { "setgroups" },
-       [82]    = { "select" },
-       [83]    = { "symlink" },
-       [84]    = { "oldlstat" },
-       [85]    = { "readlink" },
-       [86]    = { "uselib" },
-       [87]    = { "swapon" },
-       [88]    = { "reboot" },
-       [89]    = { "readdir" },
-       [91]    = { "munmap",           0x000034        },
-       [92]    = { "truncate" },
-       [93]    = { "ftruncate" },
-       [94]    = { "fchmod" },
-       [95]    = { "fchown" },
-       [96]    = { "getpriority" },
-       [97]    = { "setpriority" },
-       [99]    = { "statfs" },
-       [100]   = { "fstatfs" },
-       [102]   = { "socketcall" },
-       [103]   = { "syslog" },
-       [104]   = { "setitimer" },
-       [105]   = { "getitimer" },
-       [106]   = { "stat" },
-       [107]   = { "lstat" },
-       [108]   = { "fstat" },
-       [111]   = { "vhangup" },
-       [114]   = { "wait4" },
-       [115]   = { "swapoff" },
-       [116]   = { "sysinfo" },
-       [117]   = { "ipc" },
-       [118]   = { "fsync" },
-       [119]   = { "sigreturn" },
-       [120]   = { "clone" },
-       [121]   = { "setdomainname" },
-       [122]   = { "uname" },
-       [123]   = { "modify_ldt" },
-       [123]   = { "cacheflush" },
-       [124]   = { "adjtimex" },
-       [125]   = { "mprotect" },
-       [126]   = { "sigprocmask" },
-       [127]   = { "create_module" },
-       [128]   = { "init_module" },
-       [129]   = { "delete_module" },
-       [130]   = { "get_kernel_syms" },
-       [131]   = { "quotactl" },
-       [132]   = { "getpgid" },
-       [133]   = { "fchdir" },
-       [134]   = { "bdflush" },
-       [135]   = { "sysfs" },
-       [136]   = { "personality" },
-       [137]   = { "afs_syscall" },
-       [138]   = { "setfsuid" },
-       [139]   = { "setfsgid" },
-       [140]   = { "_llseek",                  0x014331        },
-       [141]   = { "getdents" },
-       [142]   = { "_newselect",               0x000141        },
-       [143]   = { "flock" },
-       [144]   = { "msync" },
-       [145]   = { "readv" },
-       [146]   = { "writev" },
-       [147]   = { "getsid",                   0x000001        },
-       [148]   = { "fdatasync",                0x000001        },
-       [149]   = { "_sysctl",                  0x000004        },
-       [150]   = { "mlock" },
-       [151]   = { "munlock" },
-       [152]   = { "mlockall" },
-       [153]   = { "munlockall" },
-       [154]   = { "sched_setparam" },
-       [155]   = { "sched_getparam" },
-       [156]   = { "sched_setscheduler" },
-       [157]   = { "sched_getscheduler" },
-       [158]   = { "sched_yield" },
-       [159]   = { "sched_get_priority_max" },
-       [160]   = { "sched_get_priority_min" },
-       [161]   = { "sched_rr_get_interval" },
-       [162]   = { "nanosleep",                0x000044        },
-       [163]   = { "mremap" },
-       [164]   = { "setresuid" },
-       [165]   = { "getresuid" },
-       [166]   = { "vm86" },
-       [167]   = { "query_module" },
-       [168]   = { "poll" },
-       [169]   = { "nfsservctl" },
-       [170]   = { "setresgid" },
-       [171]   = { "getresgid" },
-       [172]   = { "prctl",                    0x333331        },
-       [173]   = { "rt_sigreturn",             0xffffff        },
-       [174]   = { "rt_sigaction",             0x001441        },
-       [175]   = { "rt_sigprocmask",           0x001441        },
-       [176]   = { "rt_sigpending",            0x000014        },
-       [177]   = { "rt_sigtimedwait",          0x001444        },
-       [178]   = { "rt_sigqueueinfo",          0x000411        },
-       [179]   = { "rt_sigsuspend",            0x000014        },
-       [180]   = { "pread",                    0x003341        },
-       [181]   = { "pwrite",                   0x003341        },
-       [182]   = { "chown",                    0x000115        },
-       [183]   = { "getcwd" },
-       [184]   = { "capget" },
-       [185]   = { "capset" },
-       [186]   = { "sigaltstack" },
-       [187]   = { "sendfile" },
-       [188]   = { "getpmsg" },
-       [189]   = { "putpmsg" },
-       [190]   = { "vfork",                    0xffffff        },
-       [191]   = { "ugetrlimit" },
-       [192]   = { "mmap2",                    0x313314        },
-       [193]   = { "truncate64" },
-       [194]   = { "ftruncate64" },
-       [195]   = { "stat64",                   0x000045        },
-       [196]   = { "lstat64",                  0x000045        },
-       [197]   = { "fstat64",                  0x000041        },
-       [198]   = { "lchown32" },
-       [199]   = { "getuid32",                 0xffffff        },
-       [200]   = { "getgid32",                 0xffffff        },
-       [201]   = { "geteuid32",                0xffffff        },
-       [202]   = { "getegid32",                0xffffff        },
-       [203]   = { "setreuid32" },
-       [204]   = { "setregid32" },
-       [205]   = { "getgroups32" },
-       [206]   = { "setgroups32" },
-       [207]   = { "fchown32" },
-       [208]   = { "setresuid32" },
-       [209]   = { "getresuid32" },
-       [210]   = { "setresgid32" },
-       [211]   = { "getresgid32" },
-       [212]   = { "chown32" },
-       [213]   = { "setuid32" },
-       [214]   = { "setgid32" },
-       [215]   = { "setfsuid32" },
-       [216]   = { "setfsgid32" },
-       [217]   = { "pivot_root" },
-       [218]   = { "mincore" },
-       [219]   = { "madvise" },
-       [220]   = { "getdents64" },
-       [221]   = { "fcntl64" },
-       [223]   = { "security" },
-       [224]   = { "gettid" },
-       [225]   = { "readahead" },
-       [226]   = { "setxattr" },
-       [227]   = { "lsetxattr" },
-       [228]   = { "fsetxattr" },
-       [229]   = { "getxattr" },
-       [230]   = { "lgetxattr" },
-       [231]   = { "fgetxattr" },
-       [232]   = { "listxattr" },
-       [233]   = { "llistxattr" },
-       [234]   = { "flistxattr" },
-       [235]   = { "removexattr" },
-       [236]   = { "lremovexattr" },
-       [237]   = { "fremovexattr" },
-       [238]   = { "tkill" },
-       [239]   = { "sendfile64" },
-       [240]   = { "futex" },
-       [241]   = { "sched_setaffinity" },
-       [242]   = { "sched_getaffinity" },
-       [243]   = { "set_thread_area" },
-       [244]   = { "get_thread_area" },
-       [245]   = { "io_setup" },
-       [246]   = { "io_destroy" },
-       [247]   = { "io_getevents" },
-       [248]   = { "io_submit" },
-       [249]   = { "io_cancel" },
-       [250]   = { "fadvise64" },
-       [252]   = { "exit_group",               0x000001        },
-       [253]   = { "lookup_dcookie" },
-       [254]   = { "epoll_create" },
-       [255]   = { "epoll_ctl" },
-       [256]   = { "epoll_wait" },
-       [257]   = { "remap_file_pages" },
-       [258]   = { "set_tid_address" },
-       [259]   = { "timer_create" },
-       [260]   = { "timer_settime" },
-       [261]   = { "timer_gettime" },
-       [262]   = { "timer_getoverrun" },
-       [263]   = { "timer_delete" },
-       [264]   = { "clock_settime" },
-       [265]   = { "clock_gettime" },
-       [266]   = { "clock_getres" },
-       [267]   = { "clock_nanosleep" },
-       [268]   = { "statfs64" },
-       [269]   = { "fstatfs64" },
-       [270]   = { "tgkill" },
-       [271]   = { "utimes" },
-       [272]   = { "fadvise64_64" },
-       [273]   = { "vserver" },
-       [274]   = { "mbind" },
-       [275]   = { "get_mempolicy" },
-       [276]   = { "set_mempolicy" },
-       [277]   = { "mq_open" },
-       [278]   = { "mq_unlink" },
-       [279]   = { "mq_timedsend" },
-       [280]   = { "mq_timedreceive" },
-       [281]   = { "mq_notify" },
-       [282]   = { "mq_getsetattr" },
-       [283]   = { "sys_kexec_load" },
-};
-
-asmlinkage void do_syscall_trace(int leaving)
+/*
+ * handle tracing of system call entry
+ * - return the revised system call number or ULONG_MAX to cause ENOSYS
+ */
+asmlinkage unsigned long syscall_trace_entry(void)
 {
-#if 0
-       unsigned long *argp;
-       const char *name;
-       unsigned argmask;
-       char buffer[16];
-
-       if (!kstrace)
-               return;
-
-       if (!current->mm)
-               return;
-
-       if (__frame->gr7 == __NR_close)
-               return;
-
-#if 0
-       if (__frame->gr7 != __NR_mmap2 &&
-           __frame->gr7 != __NR_vfork &&
-           __frame->gr7 != __NR_execve &&
-           __frame->gr7 != __NR_exit)
-               return;
-#endif
-
-       argmask = 0;
-       name = NULL;
-       if (__frame->gr7 < NR_syscalls) {
-               name = __syscall_name_table[__frame->gr7].name;
-               argmask = __syscall_name_table[__frame->gr7].argmask;
-       }
-       if (!name) {
-               sprintf(buffer, "sys_%lx", __frame->gr7);
-               name = buffer;
-       }
-
-       if (!leaving) {
-               if (!argmask) {
-                       printk(KERN_CRIT "[%d] %s(%lx,%lx,%lx,%lx,%lx,%lx)\n",
-                              current->pid,
-                              name,
-                              __frame->gr8,
-                              __frame->gr9,
-                              __frame->gr10,
-                              __frame->gr11,
-                              __frame->gr12,
-                              __frame->gr13);
-               }
-               else if (argmask == 0xffffff) {
-                       printk(KERN_CRIT "[%d] %s()\n",
-                              current->pid,
-                              name);
-               }
-               else {
-                       printk(KERN_CRIT "[%d] %s(",
-                              current->pid,
-                              name);
-
-                       argp = &__frame->gr8;
-
-                       do {
-                               switch (argmask & 0xf) {
-                               case 1:
-                                       printk("%ld", (long) *argp);
-                                       break;
-                               case 2:
-                                       printk("%lo", *argp);
-                                       break;
-                               case 3:
-                                       printk("%lx", *argp);
-                                       break;
-                               case 4:
-                                       printk("%p", (void *) *argp);
-                                       break;
-                               case 5:
-                                       printk("\"%s\"", (char *) *argp);
-                                       break;
-                               }
-
-                               argp++;
-                               argmask >>= 4;
-                               if (argmask)
-                                       printk(",");
-
-                       } while (argmask);
-
-                       printk(")\n");
-               }
-       }
-       else {
-               if ((int)__frame->gr8 > -4096 && (int)__frame->gr8 < 4096)
-                       printk(KERN_CRIT "[%d] %s() = %ld\n", current->pid, name, __frame->gr8);
-               else
-                       printk(KERN_CRIT "[%d] %s() = %lx\n", current->pid, name, __frame->gr8);
+       __frame->__status |= REG__STATUS_SYSC_ENTRY;
+       if (tracehook_report_syscall_entry(__frame)) {
+               /* tracing decided this syscall should not happen, so
+                * We'll return a bogus call number to get an ENOSYS
+                * error, but leave the original number in
+                * __frame->syscallno
+                */
+               return ULONG_MAX;
        }
-       return;
-#endif
-
-       if (!test_thread_flag(TIF_SYSCALL_TRACE))
-               return;
-
-       if (!(current->ptrace & PT_PTRACED))
-               return;
 
-       /* we need to indicate entry or exit to strace */
-       if (leaving)
-               __frame->__status |= REG__STATUS_SYSC_EXIT;
-       else
-               __frame->__status |= REG__STATUS_SYSC_ENTRY;
-
-       ptrace_notify(SIGTRAP);
+       return __frame->syscallno;
+}
 
-       /*
-        * this isn't the same as continuing with a signal, but it will do
-        * for normal use.  strace only continues with a signal if the
-        * stopping signal is not SIGTRAP.  -brl
-        */
-       if (current->exit_code) {
-               send_sig(current->exit_code, current, 1);
-               current->exit_code = 0;
-       }
+/*
+ * handle tracing of system call exit
+ */
+asmlinkage void syscall_trace_exit(void)
+{
+       __frame->__status |= REG__STATUS_SYSC_EXIT;
+       tracehook_report_syscall_exit(__frame, 0);
 }
index 3bdb368292a8c8a53f9c00b3aa39dc169420b095..4a7a62c6e7833ed91a9087b3762cb3d0ba24df5f 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/unistd.h>
 #include <linux/personality.h>
 #include <linux/freezer.h>
+#include <linux/tracehook.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
@@ -516,6 +517,9 @@ static void do_signal(void)
                         * clear the TIF_RESTORE_SIGMASK flag */
                        if (test_thread_flag(TIF_RESTORE_SIGMASK))
                                clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+                       tracehook_signal_handler(signr, &info, &ka, __frame,
+                                                test_thread_flag(TIF_SINGLESTEP));
                }
 
                return;
@@ -564,4 +568,10 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags)
        if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
                do_signal();
 
+       /* deal with notification on about to resume userspace execution */
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(__frame);
+       }
+
 } /* end do_notify_resume() */
index 9fb771a20df3cf831f4779aba7859e4c865928de..374f88d6cc00d0c32fffd03f5c7b3a8b1af395ee 100644 (file)
@@ -23,8 +23,7 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
        char *p, ch;
        long err = -EFAULT;
 
-       if (count < 0)
-               BUG();
+       BUG_ON(count < 0);
 
        p = dst;
 
@@ -76,8 +75,7 @@ long strnlen_user(const char __user *src, long count)
        long err = 0;
        char ch;
 
-       if (count < 0)
-               BUG();
+       BUG_ON(count < 0);
 
 #ifndef CONFIG_MMU
        if ((unsigned long) src < memory_start)
index 52ff9aec799d29c84a649aa128ccb985b60cd68c..4e1ba0b15443a86ac4f5fd12bb34b552c392a768 100644 (file)
@@ -116,8 +116,7 @@ EXPORT_SYMBOL(dma_free_coherent);
 dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
                          enum dma_data_direction direction)
 {
-       if (direction == DMA_NONE)
-                BUG();
+       BUG_ON(direction == DMA_NONE);
 
        frv_cache_wback_inv((unsigned long) ptr, (unsigned long) ptr + size);
 
@@ -151,8 +150,7 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
                frv_cache_wback_inv(sg_dma_address(&sg[i]),
                                    sg_dma_address(&sg[i]) + sg_dma_len(&sg[i]));
 
-       if (direction == DMA_NONE)
-                BUG();
+       BUG_ON(direction == DMA_NONE);
 
        return nents;
 }
index 3ddedebc4eb3db1a1bbc25a7a10dd2e1fd1e66e5..45954f0813dc9e75a5e15f06e5cdb13776170c30 100644 (file)
@@ -48,8 +48,7 @@ EXPORT_SYMBOL(dma_free_coherent);
 dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
                          enum dma_data_direction direction)
 {
-       if (direction == DMA_NONE)
-                BUG();
+       BUG_ON(direction == DMA_NONE);
 
        frv_cache_wback_inv((unsigned long) ptr, (unsigned long) ptr + size);
 
@@ -81,8 +80,7 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
        void *vaddr;
        int i;
 
-       if (direction == DMA_NONE)
-                BUG();
+       BUG_ON(direction == DMA_NONE);
 
        dampr2 = __get_DAMPR(2);
 
index cc0a3182db3c0158d246f658065a0f0f5d426a5f..acb5047ab57341d9818160f361db47c7e6e59313 100644 (file)
@@ -21,9 +21,10 @@ hpsim_irq_noop (unsigned int irq)
 {
 }
 
-static void
+static int
 hpsim_set_affinity_noop(unsigned int a, const struct cpumask *b)
 {
+       return 0;
 }
 
 static struct hw_interrupt_type irq_type_hp_sim = {
index 4542651e6acb1e82f3f4665ebca0705a9e6161aa..5f43697aed3018f5d821a10d641642de88473c32 100644 (file)
@@ -371,6 +371,7 @@ struct kvm_vcpu_arch {
        int last_run_cpu;
        int vmm_tr_slot;
        int vm_tr_slot;
+       int sn_rtc_tr_slot;
 
 #define KVM_MP_STATE_RUNNABLE          0
 #define KVM_MP_STATE_UNINITIALIZED     1
@@ -465,6 +466,7 @@ struct kvm_arch {
        unsigned long   vmm_init_rr;
 
        int             online_vcpus;
+       int             is_sn2;
 
        struct kvm_ioapic *vioapic;
        struct kvm_vm_stat stat;
@@ -472,6 +474,7 @@ struct kvm_arch {
 
        struct list_head assigned_dev_head;
        struct iommu_domain *iommu_domain;
+       int iommu_flags;
        struct hlist_head irq_ack_notifier_list;
 
        unsigned long irq_sources_bitmap;
@@ -578,6 +581,8 @@ struct kvm_vmm_info{
        kvm_vmm_entry   *vmm_entry;
        kvm_tramp_entry *tramp_entry;
        unsigned long   vmm_ivt;
+       unsigned long   patch_mov_ar;
+       unsigned long   patch_mov_ar_sn2;
 };
 
 int kvm_highest_pending_irq(struct kvm_vcpu *vcpu);
@@ -585,7 +590,6 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu);
 int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run);
 void kvm_sal_emul(struct kvm_vcpu *vcpu);
 
-static inline void kvm_inject_nmi(struct kvm_vcpu *vcpu) {}
 #endif /* __ASSEMBLY__*/
 
 #endif
index 7a9bff47564f10c3165123e378ce226e90d55f2b..0a9cc73d35c78fac88f4733511021849a0b2a248 100644 (file)
 #define PAGE_GATE      __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_X_RX)
 #define PAGE_KERNEL    __pgprot(__DIRTY_BITS  | _PAGE_PL_0 | _PAGE_AR_RWX)
 #define PAGE_KERNELRX  __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_RX)
+#define PAGE_KERNEL_UC __pgprot(__DIRTY_BITS  | _PAGE_PL_0 | _PAGE_AR_RWX | \
+                                _PAGE_MA_UC)
 
 # ifndef __ASSEMBLY__
 
index 5510317db37b2a439711bb3fa97d6af0c7cd00bf..baec6f00f7f3feee71c5110b01f12b5c8b3f4fda 100644 (file)
@@ -636,7 +636,7 @@ void __init acpi_numa_arch_fixup(void)
  * success: return IRQ number (>=0)
  * failure: return < 0
  */
-int acpi_register_gsi(u32 gsi, int triggering, int polarity)
+int acpi_register_gsi(struct device *dev, u32 gsi, int triggering, int polarity)
 {
        if (acpi_irq_model == ACPI_IRQ_MODEL_PLATFORM)
                return gsi;
@@ -678,7 +678,8 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table)
 
        fadt = (struct acpi_table_fadt *)fadt_header;
 
-       acpi_register_gsi(fadt->sci_interrupt, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
+       acpi_register_gsi(NULL, fadt->sci_interrupt, ACPI_LEVEL_SENSITIVE,
+                                ACPI_ACTIVE_LOW);
        return 0;
 }
 
index 166e0d839fa04d753fa3709bfe62544eee32e9ec..f92cef47bf862ed8cd3943875585535e0c412763 100644 (file)
@@ -329,7 +329,7 @@ unmask_irq (unsigned int irq)
 }
 
 
-static void
+static int
 iosapic_set_affinity(unsigned int irq, const struct cpumask *mask)
 {
 #ifdef CONFIG_SMP
@@ -343,15 +343,15 @@ iosapic_set_affinity(unsigned int irq, const struct cpumask *mask)
 
        cpu = cpumask_first_and(cpu_online_mask, mask);
        if (cpu >= nr_cpu_ids)
-               return;
+               return -1;
 
        if (irq_prepare_move(irq, cpu))
-               return;
+               return -1;
 
        dest = cpu_physical_id(cpu);
 
        if (!iosapic_intr_info[irq].count)
-               return;                 /* not an IOSAPIC interrupt */
+               return -1;                      /* not an IOSAPIC interrupt */
 
        set_irq_affinity_info(irq, dest, redir);
 
@@ -376,7 +376,9 @@ iosapic_set_affinity(unsigned int irq, const struct cpumask *mask)
                iosapic_write(iosapic, IOSAPIC_RTE_HIGH(rte_index), high32);
                iosapic_write(iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
        }
+
 #endif
+       return 0;
 }
 
 /*
index acc4d19ae62ad17fd956f914a0829a6bda3b8589..b448197728be5cc22b91fd92f2c49d2cee0f455f 100644 (file)
@@ -610,6 +610,9 @@ static struct irqaction ipi_irqaction = {
        .name =         "IPI"
 };
 
+/*
+ * KVM uses this interrupt to force a cpu out of guest mode
+ */
 static struct irqaction resched_irqaction = {
        .handler =      dummy_handler,
        .flags =        IRQF_DISABLED,
index 2b15e233f7fef6b016f50367c90f9c91ba096b63..0f8ade9331badf4acaf29818dcad0dc67b31fd5e 100644 (file)
@@ -12,7 +12,7 @@
 static struct irq_chip ia64_msi_chip;
 
 #ifdef CONFIG_SMP
-static void ia64_set_msi_irq_affinity(unsigned int irq,
+static int ia64_set_msi_irq_affinity(unsigned int irq,
                                      const cpumask_t *cpu_mask)
 {
        struct msi_msg msg;
@@ -20,10 +20,10 @@ static void ia64_set_msi_irq_affinity(unsigned int irq,
        int cpu = first_cpu(*cpu_mask);
 
        if (!cpu_online(cpu))
-               return;
+               return -1;
 
        if (irq_prepare_move(irq, cpu))
-               return;
+               return -1;
 
        read_msi_msg(irq, &msg);
 
@@ -39,6 +39,8 @@ static void ia64_set_msi_irq_affinity(unsigned int irq,
 
        write_msi_msg(irq, &msg);
        cpumask_copy(irq_desc[irq].affinity, cpumask_of(cpu));
+
+       return 0;
 }
 #endif /* CONFIG_SMP */
 
@@ -130,17 +132,17 @@ void arch_teardown_msi_irq(unsigned int irq)
 
 #ifdef CONFIG_DMAR
 #ifdef CONFIG_SMP
-static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
+static int dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
 {
        struct irq_cfg *cfg = irq_cfg + irq;
        struct msi_msg msg;
        int cpu = cpumask_first(mask);
 
        if (!cpu_online(cpu))
-               return;
+               return -1;
 
        if (irq_prepare_move(irq, cpu))
-               return;
+               return -1;
 
        dmar_msi_read(irq, &msg);
 
@@ -151,6 +153,8 @@ static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
 
        dmar_msi_write(irq, &msg);
        cpumask_copy(irq_desc[irq].affinity, mask);
+
+       return 0;
 }
 #endif /* CONFIG_SMP */
 
index 0a2d6b86075a66ce45908ee6fc66f2cd981b4c8c..64d5209378749ff7175f8218fdbb546ee6310315 100644 (file)
@@ -23,7 +23,7 @@ if VIRTUALIZATION
 
 config KVM
        tristate "Kernel-based Virtual Machine (KVM) support"
-       depends on HAVE_KVM && EXPERIMENTAL
+       depends on HAVE_KVM && MODULES && EXPERIMENTAL
        # for device assignment:
        depends on PCI
        select PREEMPT_NOTIFIERS
index d20a5db4c4dde90674debfd2eb370b4434870b89..80c57b0a21c479ee593fb095bc8429089eced2f5 100644 (file)
@@ -41,6 +41,9 @@
 #include <asm/div64.h>
 #include <asm/tlb.h>
 #include <asm/elf.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/shub_mmr.h>
 
 #include "misc.h"
 #include "vti.h"
@@ -65,6 +68,16 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { NULL }
 };
 
+static unsigned long kvm_get_itc(struct kvm_vcpu *vcpu)
+{
+#if defined(CONFIG_IA64_SGI_SN2) || defined(CONFIG_IA64_GENERIC)
+       if (vcpu->kvm->arch.is_sn2)
+               return rtc_time();
+       else
+#endif
+               return ia64_getreg(_IA64_REG_AR_ITC);
+}
+
 static void kvm_flush_icache(unsigned long start, unsigned long len)
 {
        int l;
@@ -119,8 +132,7 @@ void kvm_arch_hardware_enable(void *garbage)
        unsigned long saved_psr;
        int slot;
 
-       pte = pte_val(mk_pte_phys(__pa(kvm_vmm_base),
-                               PAGE_KERNEL));
+       pte = pte_val(mk_pte_phys(__pa(kvm_vmm_base), PAGE_KERNEL));
        local_irq_save(saved_psr);
        slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT);
        local_irq_restore(saved_psr);
@@ -283,6 +295,18 @@ static int handle_sal_call(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
 }
 
+static int __apic_accept_irq(struct kvm_vcpu *vcpu, uint64_t vector)
+{
+       struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd);
+
+       if (!test_and_set_bit(vector, &vpd->irr[0])) {
+               vcpu->arch.irq_new_pending = 1;
+               kvm_vcpu_kick(vcpu);
+               return 1;
+       }
+       return 0;
+}
+
 /*
  *  offset: address offset to IPI space.
  *  value:  deliver value.
@@ -292,20 +316,20 @@ static void vcpu_deliver_ipi(struct kvm_vcpu *vcpu, uint64_t dm,
 {
        switch (dm) {
        case SAPIC_FIXED:
-               kvm_apic_set_irq(vcpu, vector, 0);
                break;
        case SAPIC_NMI:
-               kvm_apic_set_irq(vcpu, 2, 0);
+               vector = 2;
                break;
        case SAPIC_EXTINT:
-               kvm_apic_set_irq(vcpu, 0, 0);
+               vector = 0;
                break;
        case SAPIC_INIT:
        case SAPIC_PMI:
        default:
                printk(KERN_ERR"kvm: Unimplemented Deliver reserved IPI!\n");
-               break;
+               return;
        }
+       __apic_accept_irq(vcpu, vector);
 }
 
 static struct kvm_vcpu *lid_to_vcpu(struct kvm *kvm, unsigned long id,
@@ -413,6 +437,23 @@ static int handle_switch_rr6(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 1;
 }
 
+static int kvm_sn2_setup_mappings(struct kvm_vcpu *vcpu)
+{
+       unsigned long pte, rtc_phys_addr, map_addr;
+       int slot;
+
+       map_addr = KVM_VMM_BASE + (1UL << KVM_VMM_SHIFT);
+       rtc_phys_addr = LOCAL_MMR_OFFSET | SH_RTC;
+       pte = pte_val(mk_pte_phys(rtc_phys_addr, PAGE_KERNEL_UC));
+       slot = ia64_itr_entry(0x3, map_addr, pte, PAGE_SHIFT);
+       vcpu->arch.sn_rtc_tr_slot = slot;
+       if (slot < 0) {
+               printk(KERN_ERR "Mayday mayday! RTC mapping failed!\n");
+               slot = 0;
+       }
+       return slot;
+}
+
 int kvm_emulate_halt(struct kvm_vcpu *vcpu)
 {
 
@@ -426,7 +467,7 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu)
 
        if (irqchip_in_kernel(vcpu->kvm)) {
 
-               vcpu_now_itc = ia64_getreg(_IA64_REG_AR_ITC) + vcpu->arch.itc_offset;
+               vcpu_now_itc = kvm_get_itc(vcpu) + vcpu->arch.itc_offset;
 
                if (time_after(vcpu_now_itc, vpd->itm)) {
                        vcpu->arch.timer_check = 1;
@@ -447,10 +488,10 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu)
                hrtimer_cancel(p_ht);
                vcpu->arch.ht_active = 0;
 
-               if (test_and_clear_bit(KVM_REQ_UNHALT, &vcpu->requests))
+               if (test_and_clear_bit(KVM_REQ_UNHALT, &vcpu->requests) ||
+                               kvm_cpu_has_pending_timer(vcpu))
                        if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED)
-                               vcpu->arch.mp_state =
-                                       KVM_MP_STATE_RUNNABLE;
+                               vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
 
                if (vcpu->arch.mp_state != KVM_MP_STATE_RUNNABLE)
                        return -EINTR;
@@ -551,22 +592,35 @@ static int kvm_insert_vmm_mapping(struct kvm_vcpu *vcpu)
        if (r < 0)
                goto out;
        vcpu->arch.vm_tr_slot = r;
+
+#if defined(CONFIG_IA64_SGI_SN2) || defined(CONFIG_IA64_GENERIC)
+       if (kvm->arch.is_sn2) {
+               r = kvm_sn2_setup_mappings(vcpu);
+               if (r < 0)
+                       goto out;
+       }
+#endif
+
        r = 0;
 out:
        return r;
-
 }
 
 static void kvm_purge_vmm_mapping(struct kvm_vcpu *vcpu)
 {
-
+       struct kvm *kvm = vcpu->kvm;
        ia64_ptr_entry(0x3, vcpu->arch.vmm_tr_slot);
        ia64_ptr_entry(0x3, vcpu->arch.vm_tr_slot);
-
+#if defined(CONFIG_IA64_SGI_SN2) || defined(CONFIG_IA64_GENERIC)
+       if (kvm->arch.is_sn2)
+               ia64_ptr_entry(0x3, vcpu->arch.sn_rtc_tr_slot);
+#endif
 }
 
 static int kvm_vcpu_pre_transition(struct kvm_vcpu *vcpu)
 {
+       unsigned long psr;
+       int r;
        int cpu = smp_processor_id();
 
        if (vcpu->arch.last_run_cpu != cpu ||
@@ -578,36 +632,27 @@ static int kvm_vcpu_pre_transition(struct kvm_vcpu *vcpu)
 
        vcpu->arch.host_rr6 = ia64_get_rr(RR6);
        vti_set_rr6(vcpu->arch.vmm_rr);
-       return kvm_insert_vmm_mapping(vcpu);
+       local_irq_save(psr);
+       r = kvm_insert_vmm_mapping(vcpu);
+       local_irq_restore(psr);
+       return r;
 }
+
 static void kvm_vcpu_post_transition(struct kvm_vcpu *vcpu)
 {
        kvm_purge_vmm_mapping(vcpu);
        vti_set_rr6(vcpu->arch.host_rr6);
 }
 
-static int  vti_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
        union context *host_ctx, *guest_ctx;
        int r;
 
-       /*Get host and guest context with guest address space.*/
-       host_ctx = kvm_get_host_context(vcpu);
-       guest_ctx = kvm_get_guest_context(vcpu);
-
-       r = kvm_vcpu_pre_transition(vcpu);
-       if (r < 0)
-               goto out;
-       kvm_vmm_info->tramp_entry(host_ctx, guest_ctx);
-       kvm_vcpu_post_transition(vcpu);
-       r = 0;
-out:
-       return r;
-}
-
-static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-       int r;
+       /*
+        * down_read() may sleep and return with interrupts enabled
+        */
+       down_read(&vcpu->kvm->slots_lock);
 
 again:
        if (signal_pending(current)) {
@@ -616,26 +661,31 @@ again:
                goto out;
        }
 
-       /*
-        * down_read() may sleep and return with interrupts enabled
-        */
-       down_read(&vcpu->kvm->slots_lock);
-
        preempt_disable();
        local_irq_disable();
 
-       vcpu->guest_mode = 1;
+       /*Get host and guest context with guest address space.*/
+       host_ctx = kvm_get_host_context(vcpu);
+       guest_ctx = kvm_get_guest_context(vcpu);
+
+       clear_bit(KVM_REQ_KICK, &vcpu->requests);
+
+       r = kvm_vcpu_pre_transition(vcpu);
+       if (r < 0)
+               goto vcpu_run_fail;
+
+       up_read(&vcpu->kvm->slots_lock);
        kvm_guest_enter();
-       r = vti_vcpu_run(vcpu, kvm_run);
-       if (r < 0) {
-               local_irq_enable();
-               preempt_enable();
-               kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
-               goto out;
-       }
+
+       /*
+        * Transition to the guest
+        */
+       kvm_vmm_info->tramp_entry(host_ctx, guest_ctx);
+
+       kvm_vcpu_post_transition(vcpu);
 
        vcpu->arch.launched = 1;
-       vcpu->guest_mode = 0;
+       set_bit(KVM_REQ_KICK, &vcpu->requests);
        local_irq_enable();
 
        /*
@@ -646,9 +696,10 @@ again:
         */
        barrier();
        kvm_guest_exit();
-       up_read(&vcpu->kvm->slots_lock);
        preempt_enable();
 
+       down_read(&vcpu->kvm->slots_lock);
+
        r = kvm_handle_exit(kvm_run, vcpu);
 
        if (r > 0) {
@@ -657,12 +708,20 @@ again:
        }
 
 out:
+       up_read(&vcpu->kvm->slots_lock);
        if (r > 0) {
                kvm_resched(vcpu);
+               down_read(&vcpu->kvm->slots_lock);
                goto again;
        }
 
        return r;
+
+vcpu_run_fail:
+       local_irq_enable();
+       preempt_enable();
+       kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+       goto out;
 }
 
 static void kvm_set_mmio_data(struct kvm_vcpu *vcpu)
@@ -788,6 +847,9 @@ struct  kvm *kvm_arch_create_vm(void)
 
        if (IS_ERR(kvm))
                return ERR_PTR(-ENOMEM);
+
+       kvm->arch.is_sn2 = ia64_platform_is("sn2");
+
        kvm_init_vm(kvm);
 
        kvm->arch.online_vcpus = 0;
@@ -884,7 +946,7 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        RESTORE_REGS(saved_gp);
 
        vcpu->arch.irq_new_pending = 1;
-       vcpu->arch.itc_offset = regs->saved_itc - ia64_getreg(_IA64_REG_AR_ITC);
+       vcpu->arch.itc_offset = regs->saved_itc - kvm_get_itc(vcpu);
        set_bit(KVM_REQ_RESUME, &vcpu->requests);
 
        vcpu_put(vcpu);
@@ -1043,10 +1105,6 @@ static void kvm_free_vmm_area(void)
        }
 }
 
-static void vti_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
-{
-}
-
 static int vti_init_vpd(struct kvm_vcpu *vcpu)
 {
        int i;
@@ -1165,7 +1223,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
                regs->cr_iip = PALE_RESET_ENTRY;
 
                /*Initialize itc offset for vcpus*/
-               itc_offset = 0UL - ia64_getreg(_IA64_REG_AR_ITC);
+               itc_offset = 0UL - kvm_get_itc(vcpu);
                for (i = 0; i < kvm->arch.online_vcpus; i++) {
                        v = (struct kvm_vcpu *)((char *)vcpu +
                                        sizeof(struct kvm_vcpu_data) * i);
@@ -1237,6 +1295,7 @@ static int vti_vcpu_setup(struct kvm_vcpu *vcpu, int id)
 
        local_irq_save(psr);
        r = kvm_insert_vmm_mapping(vcpu);
+       local_irq_restore(psr);
        if (r)
                goto fail;
        r = kvm_vcpu_init(vcpu, vcpu->kvm, id);
@@ -1254,13 +1313,11 @@ static int vti_vcpu_setup(struct kvm_vcpu *vcpu, int id)
                goto uninit;
 
        kvm_purge_vmm_mapping(vcpu);
-       local_irq_restore(psr);
 
        return 0;
 uninit:
        kvm_vcpu_uninit(vcpu);
 fail:
-       local_irq_restore(psr);
        return r;
 }
 
@@ -1291,7 +1348,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
        vcpu->kvm = kvm;
 
        cpu = get_cpu();
-       vti_vcpu_load(vcpu, cpu);
        r = vti_vcpu_setup(vcpu, id);
        put_cpu();
 
@@ -1427,7 +1483,7 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        }
        for (i = 0; i < 4; i++)
                regs->insvc[i] = vcpu->arch.insvc[i];
-       regs->saved_itc = vcpu->arch.itc_offset + ia64_getreg(_IA64_REG_AR_ITC);
+       regs->saved_itc = vcpu->arch.itc_offset + kvm_get_itc(vcpu);
        SAVE_REGS(xtp);
        SAVE_REGS(metaphysical_rr0);
        SAVE_REGS(metaphysical_rr4);
@@ -1574,6 +1630,7 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
 
 void kvm_arch_flush_shadow(struct kvm *kvm)
 {
+       kvm_flush_remote_tlbs(kvm);
 }
 
 long kvm_arch_dev_ioctl(struct file *filp,
@@ -1616,8 +1673,37 @@ out:
        return 0;
 }
 
+
+/*
+ * On SN2, the ITC isn't stable, so copy in fast path code to use the
+ * SN2 RTC, replacing the ITC based default verion.
+ */
+static void kvm_patch_vmm(struct kvm_vmm_info *vmm_info,
+                         struct module *module)
+{
+       unsigned long new_ar, new_ar_sn2;
+       unsigned long module_base;
+
+       if (!ia64_platform_is("sn2"))
+               return;
+
+       module_base = (unsigned long)module->module_core;
+
+       new_ar = kvm_vmm_base + vmm_info->patch_mov_ar - module_base;
+       new_ar_sn2 = kvm_vmm_base + vmm_info->patch_mov_ar_sn2 - module_base;
+
+       printk(KERN_INFO "kvm: Patching ITC emulation to use SGI SN2 RTC "
+              "as source\n");
+
+       /*
+        * Copy the SN2 version of mov_ar into place. They are both
+        * the same size, so 6 bundles is sufficient (6 * 0x10).
+        */
+       memcpy((void *)new_ar, (void *)new_ar_sn2, 0x60);
+}
+
 static int kvm_relocate_vmm(struct kvm_vmm_info *vmm_info,
-                                               struct module *module)
+                           struct module *module)
 {
        unsigned long module_base;
        unsigned long vmm_size;
@@ -1639,6 +1725,7 @@ static int kvm_relocate_vmm(struct kvm_vmm_info *vmm_info,
                return -EFAULT;
 
        memcpy((void *)kvm_vmm_base, (void *)module_base, vmm_size);
+       kvm_patch_vmm(vmm_info, module);
        kvm_flush_icache(kvm_vmm_base, vmm_size);
 
        /*Recalculate kvm_vmm_info based on new VMM*/
@@ -1792,38 +1879,24 @@ void kvm_arch_hardware_unsetup(void)
 {
 }
 
-static void vcpu_kick_intr(void *info)
-{
-#ifdef DEBUG
-       struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info;
-       printk(KERN_DEBUG"vcpu_kick_intr %p \n", vcpu);
-#endif
-}
-
 void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
 {
-       int ipi_pcpu = vcpu->cpu;
-       int cpu = get_cpu();
+       int me;
+       int cpu = vcpu->cpu;
 
        if (waitqueue_active(&vcpu->wq))
                wake_up_interruptible(&vcpu->wq);
 
-       if (vcpu->guest_mode && cpu != ipi_pcpu)
-               smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0);
+       me = get_cpu();
+       if (cpu != me && (unsigned) cpu < nr_cpu_ids && cpu_online(cpu))
+               if (!test_and_set_bit(KVM_REQ_KICK, &vcpu->requests))
+                       smp_send_reschedule(cpu);
        put_cpu();
 }
 
-int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig)
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq)
 {
-
-       struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd);
-
-       if (!test_and_set_bit(vec, &vpd->irr[0])) {
-               vcpu->arch.irq_new_pending = 1;
-               kvm_vcpu_kick(vcpu);
-               return 1;
-       }
-       return 0;
+       return __apic_accept_irq(vcpu, irq->vector);
 }
 
 int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest)
@@ -1836,20 +1909,18 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
        return 0;
 }
 
-struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
-                                      unsigned long bitmap)
+int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
 {
-       struct kvm_vcpu *lvcpu = kvm->vcpus[0];
-       int i;
-
-       for (i = 1; i < kvm->arch.online_vcpus; i++) {
-               if (!kvm->vcpus[i])
-                       continue;
-               if (lvcpu->arch.xtp > kvm->vcpus[i]->arch.xtp)
-                       lvcpu = kvm->vcpus[i];
-       }
+       return vcpu1->arch.xtp - vcpu2->arch.xtp;
+}
 
-       return lvcpu;
+int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
+               int short_hand, int dest, int dest_mode)
+{
+       struct kvm_lapic *target = vcpu->arch.apic;
+       return (dest_mode == 0) ?
+               kvm_apic_match_physical_addr(target, dest) :
+               kvm_apic_match_logical_addr(target, dest);
 }
 
 static int find_highest_bits(int *dat)
@@ -1888,6 +1959,12 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
+{
+       /* do real check here */
+       return 1;
+}
+
 int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
 {
        return vcpu->arch.timer_fired;
@@ -1918,6 +1995,7 @@ static int vcpu_reset(struct kvm_vcpu *vcpu)
        long psr;
        local_irq_save(psr);
        r = kvm_insert_vmm_mapping(vcpu);
+       local_irq_restore(psr);
        if (r)
                goto fail;
 
@@ -1930,7 +2008,6 @@ static int vcpu_reset(struct kvm_vcpu *vcpu)
        kvm_purge_vmm_mapping(vcpu);
        r = 0;
 fail:
-       local_irq_restore(psr);
        return r;
 }
 
index a8ae52ed56358e3e3d1b81edf095ebfceaa36a3b..e4b82319881db227044550b3330f1eea69770f50 100644 (file)
@@ -21,6 +21,9 @@
 
 #include <linux/kvm_host.h>
 #include <linux/smp.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/shub_mmr.h>
 
 #include "vti.h"
 #include "misc.h"
@@ -188,12 +191,35 @@ static struct ia64_pal_retval pal_freq_base(struct kvm_vcpu *vcpu)
        return result;
 }
 
-static struct ia64_pal_retval pal_freq_ratios(struct kvm_vcpu *vcpu)
+/*
+ * On the SGI SN2, the ITC isn't stable. Emulation backed by the SN2
+ * RTC is used instead. This function patches the ratios from SAL
+ * to match the RTC before providing them to the guest.
+ */
+static void sn2_patch_itc_freq_ratios(struct ia64_pal_retval *result)
 {
+       struct pal_freq_ratio *ratio;
+       unsigned long sal_freq, sal_drift, factor;
+
+       result->status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
+                                           &sal_freq, &sal_drift);
+       ratio = (struct pal_freq_ratio *)&result->v2;
+       factor = ((sal_freq * 3) + (sn_rtc_cycles_per_second / 2)) /
+               sn_rtc_cycles_per_second;
+
+       ratio->num = 3;
+       ratio->den = factor;
+}
 
+static struct ia64_pal_retval pal_freq_ratios(struct kvm_vcpu *vcpu)
+{
        struct ia64_pal_retval result;
 
        PAL_CALL(result, PAL_FREQ_RATIOS, 0, 0, 0);
+
+       if (vcpu->kvm->arch.is_sn2)
+               sn2_patch_itc_freq_ratios(&result);
+
        return result;
 }
 
index 6d6cbcb14893c281952f82365779cf925cf7f0e0..ee541cebcd78aa7442aff169308a17e0259bc8c4 100644 (file)
@@ -20,6 +20,10 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu);
 
 int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
 int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
-int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig);
+int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
+               int short_hand, int dest, int dest_mode);
+int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2);
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq);
+#define kvm_apic_present(x) (true)
 
 #endif
index 32254ce9a1bda61a25f3edce6143206a7d651aa1..f793be3effff5a773c3f5586994b374d1a5d2f82 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <asm/asmmacro.h>
 #include <asm/processor.h>
+#include <asm/kvm_host.h>
 
 #include "vti.h"
 #include "asm-offsets.h"
@@ -140,6 +141,35 @@ GLOBAL_ENTRY(kvm_asm_mov_from_ar)
        ;;
 END(kvm_asm_mov_from_ar)
 
+/*
+ * Special SGI SN2 optimized version of mov_from_ar using the SN2 RTC
+ * clock as it's source for emulating the ITC. This version will be
+ * copied on top of the original version if the host is determined to
+ * be an SN2.
+ */
+GLOBAL_ENTRY(kvm_asm_mov_from_ar_sn2)
+       add r18=VMM_VCPU_ITC_OFS_OFFSET, r21
+       movl r19 = (KVM_VMM_BASE+(1<<KVM_VMM_SHIFT))
+
+       add r16=VMM_VCPU_LAST_ITC_OFFSET,r21
+       extr.u r17=r25,6,7
+       mov r24=b0
+       ;;
+       ld8 r18=[r18]
+       ld8 r19=[r19]
+       addl r20=@gprel(asm_mov_to_reg),gp
+       ;;
+       add r19=r19,r18
+       shladd r17=r17,4,r20
+       ;;
+       adds r30=kvm_resume_to_guest-asm_mov_to_reg,r20
+       st8 [r16] = r19
+       mov b0=r17
+       br.sptk.few b0
+       ;;
+END(kvm_asm_mov_from_ar_sn2)
+
+
 
 // mov r1=rr[r3]
 GLOBAL_ENTRY(kvm_asm_mov_from_rr)
index b1dc80952d91fc49918de183bbeb454276e723e7..a8f84da04b49b8baa8daed4f49bdc2e178e240be 100644 (file)
@@ -652,20 +652,25 @@ void  kvm_ia64_handle_break(unsigned long ifa, struct kvm_pt_regs *regs,
                unsigned long isr, unsigned long iim)
 {
        struct kvm_vcpu *v = current_vcpu;
+       long psr;
 
        if (ia64_psr(regs)->cpl == 0) {
                /* Allow hypercalls only when cpl = 0.  */
                if (iim == DOMN_PAL_REQUEST) {
+                       local_irq_save(psr);
                        set_pal_call_data(v);
                        vmm_transition(v);
                        get_pal_call_result(v);
                        vcpu_increment_iip(v);
+                       local_irq_restore(psr);
                        return;
                } else if (iim == DOMN_SAL_REQUEST) {
+                       local_irq_save(psr);
                        set_sal_call_data(v);
                        vmm_transition(v);
                        get_sal_call_result(v);
                        vcpu_increment_iip(v);
+                       local_irq_restore(psr);
                        return;
                }
        }
index a18ee17b9192e01f3c3f1683817be3ae775e1ca7..a2c6c15e4761871ffe98f5bba8b52b6b70691056 100644 (file)
@@ -788,13 +788,29 @@ void vcpu_set_fpreg(struct kvm_vcpu *vcpu, unsigned long reg,
                setfpreg(reg, val, regs);   /* FIXME: handle NATs later*/
 }
 
+/*
+ * The Altix RTC is mapped specially here for the vmm module
+ */
+#define SN_RTC_BASE    (u64 *)(KVM_VMM_BASE+(1UL<<KVM_VMM_SHIFT))
+static long kvm_get_itc(struct kvm_vcpu *vcpu)
+{
+#if defined(CONFIG_IA64_SGI_SN2) || defined(CONFIG_IA64_GENERIC)
+       struct kvm *kvm = (struct kvm *)KVM_VM_BASE;
+
+       if (kvm->arch.is_sn2)
+               return (*SN_RTC_BASE);
+       else
+#endif
+               return ia64_getreg(_IA64_REG_AR_ITC);
+}
+
 /************************************************************************
  * lsapic timer
  ***********************************************************************/
 u64 vcpu_get_itc(struct kvm_vcpu *vcpu)
 {
        unsigned long guest_itc;
-       guest_itc = VMX(vcpu, itc_offset) + ia64_getreg(_IA64_REG_AR_ITC);
+       guest_itc = VMX(vcpu, itc_offset) + kvm_get_itc(vcpu);
 
        if (guest_itc >= VMX(vcpu, last_itc)) {
                VMX(vcpu, last_itc) = guest_itc;
@@ -809,7 +825,7 @@ static void vcpu_set_itc(struct kvm_vcpu *vcpu, u64 val)
        struct kvm_vcpu *v;
        struct kvm *kvm;
        int i;
-       long itc_offset = val - ia64_getreg(_IA64_REG_AR_ITC);
+       long itc_offset = val - kvm_get_itc(vcpu);
        unsigned long vitv = VCPU(vcpu, itv);
 
        kvm = (struct kvm *)KVM_VM_BASE;
index 9eee5c04baccceaaf646d72922d3403cf313e2d5..f4b4c899bb6ce9d77d42d7a796931cb13e47ab03 100644 (file)
@@ -30,15 +30,19 @@ MODULE_AUTHOR("Intel");
 MODULE_LICENSE("GPL");
 
 extern char kvm_ia64_ivt;
+extern char kvm_asm_mov_from_ar;
+extern char kvm_asm_mov_from_ar_sn2;
 extern fpswa_interface_t *vmm_fpswa_interface;
 
 long vmm_sanity = 1;
 
 struct kvm_vmm_info vmm_info = {
-       .module      = THIS_MODULE,
-       .vmm_entry   = vmm_entry,
-       .tramp_entry = vmm_trampoline,
-       .vmm_ivt     = (unsigned long)&kvm_ia64_ivt,
+       .module                 = THIS_MODULE,
+       .vmm_entry              = vmm_entry,
+       .tramp_entry            = vmm_trampoline,
+       .vmm_ivt                = (unsigned long)&kvm_ia64_ivt,
+       .patch_mov_ar           = (unsigned long)&kvm_asm_mov_from_ar,
+       .patch_mov_ar_sn2       = (unsigned long)&kvm_asm_mov_from_ar_sn2,
 };
 
 static int __init  kvm_vmm_init(void)
index 3ef1a017a3189e76e713767f56d7c3a9e95fdb3c..40920c630649c3affa7556c355fea302b614f2a3 100644 (file)
@@ -95,7 +95,7 @@ GLOBAL_ENTRY(kvm_vmm_panic)
        ;;
        srlz.i    // guarantee that interruption collection is on
        ;;
-       //(p15) ssm psr.i               // restore psr.i
+       (p15) ssm psr.i               // restore psr.
        addl r14=@gprel(ia64_leave_hypervisor),gp
        ;;
        KVM_SAVE_REST
@@ -249,7 +249,7 @@ ENTRY(kvm_break_fault)
        ;;
        srlz.i         // guarantee that interruption collection is on
        ;;
-       //(p15)ssm psr.i               // restore psr.i
+       (p15)ssm psr.i               // restore psr.i
        addl r14=@gprel(ia64_leave_hypervisor),gp
        ;;
        KVM_SAVE_REST
@@ -439,7 +439,7 @@ kvm_dispatch_vexirq:
        ;;
        srlz.i // guarantee that interruption collection is on
        ;;
-       //(p15) ssm psr.i               // restore psr.i
+       (p15) ssm psr.i               // restore psr.i
        adds r3=8,r2                // set up second base pointer
        ;;
        KVM_SAVE_REST
@@ -819,7 +819,7 @@ ENTRY(kvm_dtlb_miss_dispatch)
        ;;
        srlz.i     // guarantee that interruption collection is on
        ;;
-       //(p15) ssm psr.i               // restore psr.i
+       (p15) ssm psr.i               // restore psr.i
        addl r14=@gprel(ia64_leave_hypervisor_prepare),gp
        ;;
        KVM_SAVE_REST
@@ -842,7 +842,7 @@ ENTRY(kvm_itlb_miss_dispatch)
        ;;
        srlz.i   // guarantee that interruption collection is on
        ;;
-       //(p15) ssm psr.i               // restore psr.i
+       (p15) ssm psr.i               // restore psr.i
        addl r14=@gprel(ia64_leave_hypervisor),gp
        ;;
        KVM_SAVE_REST
@@ -871,7 +871,7 @@ ENTRY(kvm_dispatch_reflection)
        ;;
        srlz.i   // guarantee that interruption collection is on
        ;;
-       //(p15) ssm psr.i               // restore psr.i
+       (p15) ssm psr.i               // restore psr.i
        addl r14=@gprel(ia64_leave_hypervisor),gp
        ;;
        KVM_SAVE_REST
@@ -898,7 +898,7 @@ ENTRY(kvm_dispatch_virtualization_fault)
        ;;
        srlz.i    // guarantee that interruption collection is on
        ;;
-       //(p15) ssm psr.i               // restore psr.i
+       (p15) ssm psr.i               // restore psr.i
        addl r14=@gprel(ia64_leave_hypervisor_prepare),gp
        ;;
        KVM_SAVE_REST
@@ -920,7 +920,7 @@ ENTRY(kvm_dispatch_interrupt)
        ;;
        srlz.i
        ;;
-       //(p15) ssm psr.i
+       (p15) ssm psr.i
        addl r14=@gprel(ia64_leave_hypervisor),gp
        ;;
        KVM_SAVE_REST
@@ -1333,7 +1333,7 @@ hostret =   r24
        ;;
 (p7)    srlz.i
        ;;
-//(p6)    ssm psr.i
+(p6)    ssm psr.i
        ;;
        mov rp=rpsave
        mov ar.pfs=pfssave
index 2c2501f131597c6389e82e6c4e3e62eb6ecf7f80..4290a429bf7c9b48f0cd9ff049d60626e23af689 100644 (file)
@@ -254,7 +254,8 @@ u64 guest_vhpt_lookup(u64 iha, u64 *pte)
                        "(p7) st8 [%2]=r9;;"
                        "ssm psr.ic;;"
                        "srlz.d;;"
-                       /* "ssm psr.i;;" Once interrupts in vmm open, need fix*/
+                       "ssm psr.i;;"
+                       "srlz.d;;"
                        : "=r"(ret) : "r"(iha), "r"(pte):"memory");
 
        return ret;
index 66fd705e82c09ee1e1905356cf447526461c086a..764f26abac05df5e9d7659ff7254da6fde398301 100644 (file)
@@ -227,7 +227,7 @@ finish_up:
        return new_irq_info;
 }
 
-static void sn_set_affinity_irq(unsigned int irq, const struct cpumask *mask)
+static int sn_set_affinity_irq(unsigned int irq, const struct cpumask *mask)
 {
        struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
        nasid_t nasid;
@@ -239,6 +239,8 @@ static void sn_set_affinity_irq(unsigned int irq, const struct cpumask *mask)
        list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
                                 sn_irq_lh[irq], list)
                (void)sn_retarget_vector(sn_irq_info, nasid, slice);
+
+       return 0;
 }
 
 #ifdef CONFIG_SMP
index 81e428943d7374d01e0aef8530e39c7ecd892b30..fbbfb970120128a29df68c549895187ea3e3013e 100644 (file)
@@ -151,7 +151,7 @@ int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry)
 }
 
 #ifdef CONFIG_SMP
-static void sn_set_msi_irq_affinity(unsigned int irq,
+static int sn_set_msi_irq_affinity(unsigned int irq,
                                    const struct cpumask *cpu_mask)
 {
        struct msi_msg msg;
@@ -168,7 +168,7 @@ static void sn_set_msi_irq_affinity(unsigned int irq,
        cpu = cpumask_first(cpu_mask);
        sn_irq_info = sn_msi_info[irq].sn_irq_info;
        if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
-               return;
+               return -1;
 
        /*
         * Release XIO resources for the old MSI PCI address
@@ -189,7 +189,7 @@ static void sn_set_msi_irq_affinity(unsigned int irq,
        new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice);
        sn_msi_info[irq].sn_irq_info = new_irq_info;
        if (new_irq_info == NULL)
-               return;
+               return -1;
 
        /*
         * Map the xio address into bus space
@@ -206,6 +206,8 @@ static void sn_set_msi_irq_affinity(unsigned int irq,
 
        write_msi_msg(irq, &msg);
        cpumask_copy(irq_desc[irq].affinity, cpu_mask);
+
+       return 0;
 }
 #endif /* CONFIG_SMP */
 
index 1c19af8daa62a3f992f20ecb1a281a527bfec3cd..d3a0c8154beca80cd7cb40bc3d783fa247891941 100644 (file)
@@ -177,7 +177,7 @@ static void octeon_irq_ciu0_disable(unsigned int irq)
 }
 
 #ifdef CONFIG_SMP
-static void octeon_irq_ciu0_set_affinity(unsigned int irq, const struct cpumask *dest)
+static int octeon_irq_ciu0_set_affinity(unsigned int irq, const struct cpumask *dest)
 {
        int cpu;
        int bit = irq - OCTEON_IRQ_WORKQ0;      /* Bit 0-63 of EN0 */
@@ -199,6 +199,8 @@ static void octeon_irq_ciu0_set_affinity(unsigned int irq, const struct cpumask
         */
        cvmx_read_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num() * 2));
        write_unlock(&octeon_irq_ciu0_rwlock);
+
+       return 0;
 }
 #endif
 
@@ -292,7 +294,7 @@ static void octeon_irq_ciu1_disable(unsigned int irq)
 }
 
 #ifdef CONFIG_SMP
-static void octeon_irq_ciu1_set_affinity(unsigned int irq, const struct cpumask *dest)
+static int octeon_irq_ciu1_set_affinity(unsigned int irq, const struct cpumask *dest)
 {
        int cpu;
        int bit = irq - OCTEON_IRQ_WDOG0;       /* Bit 0-63 of EN1 */
@@ -315,6 +317,8 @@ static void octeon_irq_ciu1_set_affinity(unsigned int irq, const struct cpumask
         */
        cvmx_read_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num() * 2 + 1));
        write_unlock(&octeon_irq_ciu1_rwlock);
+
+       return 0;
 }
 #endif
 
index 3214ade02d105988937576c8425f444b08783b0e..4f1eed107b08217f8f2991ed17f92c424b6c437f 100644 (file)
@@ -49,7 +49,7 @@ static inline void smtc_im_ack_irq(unsigned int irq)
 #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF
 #include <linux/cpumask.h>
 
-extern void plat_set_irq_affinity(unsigned int irq,
+extern int plat_set_irq_affinity(unsigned int irq,
                                  const struct cpumask *affinity);
 extern void smtc_forward_irq(unsigned int irq);
 
index 87deb8f6c45885e5c356df3ac4ddf1e58a6ac81c..3f43c2e3aa5a59ede8eab7ecdaee7762ea6afb68 100644 (file)
@@ -155,7 +155,7 @@ static void gic_unmask_irq(unsigned int irq)
 
 static DEFINE_SPINLOCK(gic_lock);
 
-static void gic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
+static int gic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
 {
        cpumask_t       tmp = CPU_MASK_NONE;
        unsigned long   flags;
@@ -166,7 +166,7 @@ static void gic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
 
        cpumask_and(&tmp, cpumask, cpu_online_mask);
        if (cpus_empty(tmp))
-               return;
+               return -1;
 
        /* Assumption : cpumask refers to a single CPU */
        spin_lock_irqsave(&gic_lock, flags);
@@ -190,6 +190,7 @@ static void gic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
        cpumask_copy(irq_desc[irq].affinity, cpumask);
        spin_unlock_irqrestore(&gic_lock, flags);
 
+       return 0;
 }
 #endif
 
index 5ba31888fefbbecacd123e7033ef8ddcb6c30944..499ffe5475dff4fe8254990499d13d6f5ff4a266 100644 (file)
@@ -114,7 +114,7 @@ struct plat_smp_ops msmtc_smp_ops = {
  */
 
 
-void plat_set_irq_affinity(unsigned int irq, const struct cpumask *affinity)
+int plat_set_irq_affinity(unsigned int irq, const struct cpumask *affinity)
 {
        cpumask_t tmask;
        int cpu = 0;
@@ -156,5 +156,7 @@ void plat_set_irq_affinity(unsigned int irq, const struct cpumask *affinity)
 
        /* Do any generic SMTC IRQ affinity setup */
        smtc_set_irq_affinity(irq, tmask);
+
+       return 0;
 }
 #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */
index c147c4b35d3fc6f9e1f48b81866eb36d7f882594..690de06bde902f38a49b8d1e1765ae3fd2251b48 100644 (file)
@@ -50,7 +50,7 @@ static void enable_bcm1480_irq(unsigned int irq);
 static void disable_bcm1480_irq(unsigned int irq);
 static void ack_bcm1480_irq(unsigned int irq);
 #ifdef CONFIG_SMP
-static void bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask);
+static int bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask);
 #endif
 
 #ifdef CONFIG_PCI
@@ -109,7 +109,7 @@ void bcm1480_unmask_irq(int cpu, int irq)
 }
 
 #ifdef CONFIG_SMP
-static void bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask)
+static int bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask)
 {
        int i = 0, old_cpu, cpu, int_on, k;
        u64 cur_ints;
@@ -118,7 +118,7 @@ static void bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask)
 
        if (cpumask_weight(mask) != 1) {
                printk("attempted to set irq affinity for irq %d to multiple CPUs\n", irq);
-               return;
+               return -1;
        }
        i = cpumask_first(mask);
 
@@ -152,6 +152,8 @@ static void bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask)
                }
        }
        spin_unlock_irqrestore(&bcm1480_imr_lock, flags);
+
+       return 0;
 }
 #endif
 
index 38cb998ade22053b8963377b70d6f7dad7fb6b94..409dec798863194f364eb378666c9e7471fd0227 100644 (file)
@@ -50,7 +50,7 @@ static void enable_sb1250_irq(unsigned int irq);
 static void disable_sb1250_irq(unsigned int irq);
 static void ack_sb1250_irq(unsigned int irq);
 #ifdef CONFIG_SMP
-static void sb1250_set_affinity(unsigned int irq, const struct cpumask *mask);
+static int sb1250_set_affinity(unsigned int irq, const struct cpumask *mask);
 #endif
 
 #ifdef CONFIG_SIBYTE_HAS_LDT
@@ -103,7 +103,7 @@ void sb1250_unmask_irq(int cpu, int irq)
 }
 
 #ifdef CONFIG_SMP
-static void sb1250_set_affinity(unsigned int irq, const struct cpumask *mask)
+static int sb1250_set_affinity(unsigned int irq, const struct cpumask *mask)
 {
        int i = 0, old_cpu, cpu, int_on;
        u64 cur_ints;
@@ -113,7 +113,7 @@ static void sb1250_set_affinity(unsigned int irq, const struct cpumask *mask)
 
        if (cpumask_weight(mask) > 1) {
                printk("attempted to set irq affinity for irq %d to multiple CPUs\n", irq);
-               return;
+               return -1;
        }
 
        /* Convert logical CPU to physical CPU */
@@ -143,6 +143,8 @@ static void sb1250_set_affinity(unsigned int irq, const struct cpumask *mask)
                                        R_IMR_INTERRUPT_MASK));
        }
        spin_unlock_irqrestore(&sb1250_imr_lock, flags);
+
+       return 0;
 }
 #endif
 
index 355926730e8d9f49387138fb2cf1cc5b9b3b8898..89faacad5d17d71871d75453fdf55d107f15985e 100644 (file)
@@ -8,6 +8,7 @@ mainmenu "Linux Kernel Configuration"
 config MN10300
        def_bool y
        select HAVE_OPROFILE
+       select HAVE_ARCH_TRACEHOOK
 
 config AM33
        def_bool y
index bf09f8bb392eef17bf41441050b5adb6e9920d0b..49105462e6fc9c5fb095fa35ad25b55493ba15a6 100644 (file)
@@ -34,7 +34,7 @@
  */
 typedef unsigned long elf_greg_t;
 
-#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+#define ELF_NGREG ((sizeof(struct pt_regs) / sizeof(elf_greg_t)) - 1)
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
 #define ELF_NFPREG 32
@@ -76,6 +76,7 @@ do {                                                                  \
 } while (0)
 
 #define USE_ELF_CORE_DUMP
+#define CORE_DUMP_USE_REGSET
 #define ELF_EXEC_PAGESIZE      4096
 
 /*
index 73239271873da304c88fe396eda7074686c3185a..f7d4b0d285e8dddb835781ac071898ff5d34dfe9 100644 (file)
@@ -143,13 +143,7 @@ extern unsigned long thread_saved_pc(struct task_struct *tsk);
 
 unsigned long get_wchan(struct task_struct *p);
 
-#define task_pt_regs(task)                                             \
-({                                                                     \
-       struct pt_regs *__regs__;                                       \
-       __regs__ = (struct pt_regs *) (KSTK_TOP(task_stack_page(task)) - 8); \
-       __regs__ - 1;                                                   \
-})
-
+#define task_pt_regs(task) ((task)->thread.uregs)
 #define KSTK_EIP(task) (task_pt_regs(task)->pc)
 #define KSTK_ESP(task) (task_pt_regs(task)->sp)
 
index 7b06cc623d8b074a3a23511673e2c170bb033840..921942ed1b03508a582e6e226ed33acf50c8fa5b 100644 (file)
@@ -91,9 +91,17 @@ extern struct pt_regs *__frame; /* current frame pointer */
 #if defined(__KERNEL__)
 
 #if !defined(__ASSEMBLY__)
+struct task_struct;
+
 #define user_mode(regs)                        (((regs)->epsw & EPSW_nSL) == EPSW_nSL)
 #define instruction_pointer(regs)      ((regs)->pc)
+#define user_stack_pointer(regs)       ((regs)->sp)
 extern void show_regs(struct pt_regs *);
+
+#define arch_has_single_step() (1)
+extern void user_enable_single_step(struct task_struct *);
+extern void user_disable_single_step(struct task_struct *);
+
 #endif  /*  !__ASSEMBLY  */
 
 #define profile_pc(regs) ((regs)->pc)
index 3dc3e462f92a4e39b496f4d78f7bc1adc6e64e85..7408a27199f342fd26679db7a326aa0b07885f53 100644 (file)
@@ -76,7 +76,7 @@ ENTRY(system_call)
        cmp     nr_syscalls,d0
        bcc     syscall_badsys
        btst    _TIF_SYSCALL_TRACE,(TI_flags,a2)
-       bne     syscall_trace_entry
+       bne     syscall_entry_trace
 syscall_call:
        add     d0,d0,a1
        add     a1,a1
@@ -104,11 +104,10 @@ restore_all:
 syscall_exit_work:
        btst    _TIF_SYSCALL_TRACE,d2
        beq     work_pending
-       __sti                           # could let do_syscall_trace() call
+       __sti                           # could let syscall_trace_exit() call
                                        # schedule() instead
        mov     fp,d0
-       mov     1,d1
-       call    do_syscall_trace[],0    # do_syscall_trace(regs,entryexit)
+       call    syscall_trace_exit[],0  # do_syscall_trace(regs)
        jmp     resume_userspace
 
        ALIGN
@@ -138,13 +137,11 @@ work_notifysig:
        jmp     resume_userspace
 
        # perform syscall entry tracing
-syscall_trace_entry:
+syscall_entry_trace:
        mov     -ENOSYS,d0
        mov     d0,(REG_D0,fp)
        mov     fp,d0
-       clr     d1
-       call    do_syscall_trace[],0
-       mov     (REG_ORIG_D0,fp),d0
+       call    syscall_trace_entry[],0 # returns the syscall number to actually use
        mov     (REG_D1,fp),d1
        cmp     nr_syscalls,d0
        bcs     syscall_call
index d6d6cdc75c523b66e6218d493311aac2afc5f017..e143339ad28e00869d9b23c1d882d994cdd89d62 100644 (file)
@@ -17,6 +17,9 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/regset.h>
+#include <linux/elf.h>
+#include <linux/tracehook.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -64,12 +67,6 @@ static inline int get_stack_long(struct task_struct *task, int offset)
                ((unsigned long) task->thread.uregs + offset);
 }
 
-/*
- * this routine will put a word on the processes privileged stack.
- * the offset is how far from the base addr as stored in the TSS.
- * this routine assumes that all the privileged stacks are in our
- * data space.
- */
 static inline
 int put_stack_long(struct task_struct *task, int offset, unsigned long data)
 {
@@ -80,94 +77,233 @@ int put_stack_long(struct task_struct *task, int offset, unsigned long data)
        return 0;
 }
 
-static inline unsigned long get_fpregs(struct fpu_state_struct *buf,
-                                      struct task_struct *tsk)
+/*
+ * retrieve the contents of MN10300 userspace general registers
+ */
+static int genregs_get(struct task_struct *target,
+                      const struct user_regset *regset,
+                      unsigned int pos, unsigned int count,
+                      void *kbuf, void __user *ubuf)
 {
-       return __copy_to_user(buf, &tsk->thread.fpu_state,
-                             sizeof(struct fpu_state_struct));
+       const struct pt_regs *regs = task_pt_regs(target);
+       int ret;
+
+       /* we need to skip regs->next */
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 regs, 0, PT_ORIG_D0 * sizeof(long));
+       if (ret < 0)
+               return ret;
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 &regs->orig_d0, PT_ORIG_D0 * sizeof(long),
+                                 NR_PTREGS * sizeof(long));
+       if (ret < 0)
+               return ret;
+
+       return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+                                       NR_PTREGS * sizeof(long), -1);
 }
 
-static inline unsigned long set_fpregs(struct task_struct *tsk,
-                                      struct fpu_state_struct *buf)
+/*
+ * update the contents of the MN10300 userspace general registers
+ */
+static int genregs_set(struct task_struct *target,
+                      const struct user_regset *regset,
+                      unsigned int pos, unsigned int count,
+                      const void *kbuf, const void __user *ubuf)
 {
-       return __copy_from_user(&tsk->thread.fpu_state, buf,
-                               sizeof(struct fpu_state_struct));
+       struct pt_regs *regs = task_pt_regs(target);
+       unsigned long tmp;
+       int ret;
+
+       /* we need to skip regs->next */
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                regs, 0, PT_ORIG_D0 * sizeof(long));
+       if (ret < 0)
+               return ret;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &regs->orig_d0, PT_ORIG_D0 * sizeof(long),
+                                PT_EPSW * sizeof(long));
+       if (ret < 0)
+               return ret;
+
+       /* we need to mask off changes to EPSW */
+       tmp = regs->epsw;
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &tmp, PT_EPSW * sizeof(long),
+                                PT_PC * sizeof(long));
+       tmp &= EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N | EPSW_FLAG_Z;
+       tmp |= regs->epsw & ~(EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N |
+                             EPSW_FLAG_Z);
+       regs->epsw = tmp;
+
+       if (ret < 0)
+               return ret;
+
+       /* and finally load the PC */
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &regs->pc, PT_PC * sizeof(long),
+                                NR_PTREGS * sizeof(long));
+
+       if (ret < 0)
+               return ret;
+
+       return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+                                        NR_PTREGS * sizeof(long), -1);
 }
 
-static inline void fpsave_init(struct task_struct *task)
+/*
+ * retrieve the contents of MN10300 userspace FPU registers
+ */
+static int fpuregs_get(struct task_struct *target,
+                      const struct user_regset *regset,
+                      unsigned int pos, unsigned int count,
+                      void *kbuf, void __user *ubuf)
 {
-       memset(&task->thread.fpu_state, 0, sizeof(struct fpu_state_struct));
+       const struct fpu_state_struct *fpregs = &target->thread.fpu_state;
+       int ret;
+
+       unlazy_fpu(target);
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 fpregs, 0, sizeof(*fpregs));
+       if (ret < 0)
+               return ret;
+
+       return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+                                       sizeof(*fpregs), -1);
 }
 
 /*
- * make sure the single step bit is not set
+ * update the contents of the MN10300 userspace FPU registers
  */
-void ptrace_disable(struct task_struct *child)
+static int fpuregs_set(struct task_struct *target,
+                      const struct user_regset *regset,
+                      unsigned int pos, unsigned int count,
+                      const void *kbuf, const void __user *ubuf)
+{
+       struct fpu_state_struct fpu_state = target->thread.fpu_state;
+       int ret;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &fpu_state, 0, sizeof(fpu_state));
+       if (ret < 0)
+               return ret;
+
+       fpu_kill_state(target);
+       target->thread.fpu_state = fpu_state;
+       set_using_fpu(target);
+
+       return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+                                        sizeof(fpu_state), -1);
+}
+
+/*
+ * determine if the FPU registers have actually been used
+ */
+static int fpuregs_active(struct task_struct *target,
+                         const struct user_regset *regset)
+{
+       return is_using_fpu(target) ? regset->n : 0;
+}
+
+/*
+ * Define the register sets available on the MN10300 under Linux
+ */
+enum mn10300_regset {
+       REGSET_GENERAL,
+       REGSET_FPU,
+};
+
+static const struct user_regset mn10300_regsets[] = {
+       /*
+        * General register format is:
+        *      A3, A2, D3, D2, MCVF, MCRL, MCRH, MDRQ
+        *      E1, E0, E7...E2, SP, LAR, LIR, MDR
+        *      A1, A0, D1, D0, ORIG_D0, EPSW, PC
+        */
+       [REGSET_GENERAL] = {
+               .core_note_type = NT_PRSTATUS,
+               .n              = ELF_NGREG,
+               .size           = sizeof(long),
+               .align          = sizeof(long),
+               .get            = genregs_get,
+               .set            = genregs_set,
+       },
+       /*
+        * FPU register format is:
+        *      FS0-31, FPCR
+        */
+       [REGSET_FPU] = {
+               .core_note_type = NT_PRFPREG,
+               .n              = sizeof(struct fpu_state_struct) / sizeof(long),
+               .size           = sizeof(long),
+               .align          = sizeof(long),
+               .get            = fpuregs_get,
+               .set            = fpuregs_set,
+               .active         = fpuregs_active,
+       },
+};
+
+static const struct user_regset_view user_mn10300_native_view = {
+       .name           = "mn10300",
+       .e_machine      = EM_MN10300,
+       .regsets        = mn10300_regsets,
+       .n              = ARRAY_SIZE(mn10300_regsets),
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+       return &user_mn10300_native_view;
+}
+
+/*
+ * set the single-step bit
+ */
+void user_enable_single_step(struct task_struct *child)
 {
 #ifndef CONFIG_MN10300_USING_JTAG
        struct user *dummy = NULL;
        long tmp;
 
        tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
-       tmp &= ~EPSW_T;
+       tmp |= EPSW_T;
        put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
 #endif
 }
 
 /*
- * set the single step bit
+ * make sure the single-step bit is not set
  */
-void ptrace_enable(struct task_struct *child)
+void user_disable_single_step(struct task_struct *child)
 {
 #ifndef CONFIG_MN10300_USING_JTAG
        struct user *dummy = NULL;
        long tmp;
 
        tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
-       tmp |= EPSW_T;
+       tmp &= ~EPSW_T;
        put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
 #endif
 }
 
+void ptrace_disable(struct task_struct *child)
+{
+       user_disable_single_step(child);
+}
+
 /*
  * handle the arch-specific side of process tracing
  */
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
-       struct fpu_state_struct fpu_state;
-       int i, ret;
+       unsigned long tmp;
+       int ret;
 
        switch (request) {
-       /* read the word at location addr. */
-       case PTRACE_PEEKTEXT: {
-               unsigned long tmp;
-               int copied;
-
-               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-               ret = -EIO;
-               if (copied != sizeof(tmp))
-                       break;
-               ret = put_user(tmp, (unsigned long *) data);
-               break;
-       }
-
-       /* read the word at location addr. */
-       case PTRACE_PEEKDATA: {
-               unsigned long tmp;
-               int copied;
-
-               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-               ret = -EIO;
-               if (copied != sizeof(tmp))
-                       break;
-               ret = put_user(tmp, (unsigned long *) data);
-               break;
-       }
-
        /* read the word at location addr in the USER area. */
-       case PTRACE_PEEKUSR: {
-               unsigned long tmp;
-
+       case PTRACE_PEEKUSR:
                ret = -EIO;
                if ((addr & 3) || addr < 0 ||
                    addr > sizeof(struct user) - 3)
@@ -179,17 +315,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                             ptrace_regid_to_frame[addr]);
                ret = put_user(tmp, (unsigned long *) data);
                break;
-       }
-
-       /* write the word at location addr. */
-       case PTRACE_POKETEXT:
-       case PTRACE_POKEDATA:
-               if (access_process_vm(child, addr, &data, sizeof(data), 1) ==
-                   sizeof(data))
-                       ret = 0;
-               else
-                       ret = -EIO;
-               break;
 
                /* write the word at location addr in the USER area */
        case PTRACE_POKEUSR:
@@ -204,132 +329,32 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                             data);
                break;
 
-               /* continue and stop at next (return from) syscall */
-       case PTRACE_SYSCALL:
-               /* restart after signal. */
-       case PTRACE_CONT:
-               ret = -EIO;
-               if ((unsigned long) data > _NSIG)
-                       break;
-               if (request == PTRACE_SYSCALL)
-                       set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               else
-                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               child->exit_code = data;
-               ptrace_disable(child);
-               wake_up_process(child);
-               ret = 0;
-               break;
-
-               /*
-                * make the child exit
-                * - the best I can do is send it a sigkill
-                * - perhaps it should be put in the status that it wants to
-                *   exit
-                */
-       case PTRACE_KILL:
-               ret = 0;
-               if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
-                       break;
-               child->exit_code = SIGKILL;
-               clear_tsk_thread_flag(child, TIF_SINGLESTEP);
-               ptrace_disable(child);
-               wake_up_process(child);
-               break;
-
-       case PTRACE_SINGLESTEP: /* set the trap flag. */
-#ifndef CONFIG_MN10300_USING_JTAG
-               ret = -EIO;
-               if ((unsigned long) data > _NSIG)
-                       break;
-               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               ptrace_enable(child);
-               child->exit_code = data;
-               wake_up_process(child);
-               ret = 0;
-#else
-               ret = -EINVAL;
-#endif
-               break;
-
-       case PTRACE_DETACH:     /* detach a process that was attached. */
-               ret = ptrace_detach(child, data);
-               break;
-
-               /* Get all gp regs from the child. */
-       case PTRACE_GETREGS: {
-               unsigned long tmp;
-
-               if (!access_ok(VERIFY_WRITE, (unsigned *) data, NR_PTREGS << 2)) {
-                       ret = -EIO;
-                       break;
-               }
-
-               for (i = 0; i < NR_PTREGS << 2; i += 4) {
-                       tmp = get_stack_long(child, ptrace_regid_to_frame[i]);
-                       __put_user(tmp, (unsigned long *) data);
-                       data += sizeof(tmp);
-               }
-               ret = 0;
-               break;
-       }
-
-       case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-               unsigned long tmp;
-
-               if (!access_ok(VERIFY_READ, (unsigned long *)data,
-                              sizeof(struct pt_regs))) {
-                       ret = -EIO;
-                       break;
-               }
-
-               for (i = 0; i < NR_PTREGS << 2; i += 4) {
-                       __get_user(tmp, (unsigned long *) data);
-                       put_stack_long(child, ptrace_regid_to_frame[i], tmp);
-                       data += sizeof(tmp);
-               }
-               ret = 0;
-               break;
-       }
-
-       case PTRACE_GETFPREGS: { /* Get the child FPU state. */
-               if (is_using_fpu(child)) {
-                       unlazy_fpu(child);
-                       fpu_state = child->thread.fpu_state;
-               } else {
-                       memset(&fpu_state, 0, sizeof(fpu_state));
-               }
-
-               ret = -EIO;
-               if (copy_to_user((void *) data, &fpu_state,
-                                sizeof(fpu_state)) == 0)
-                       ret = 0;
-               break;
-       }
-
-       case PTRACE_SETFPREGS: { /* Set the child FPU state. */
-               ret = -EFAULT;
-               if (copy_from_user(&fpu_state, (const void *) data,
-                                  sizeof(fpu_state)) == 0) {
-                       fpu_kill_state(child);
-                       child->thread.fpu_state = fpu_state;
-                       set_using_fpu(child);
-                       ret = 0;
-               }
-               break;
-       }
-
-       case PTRACE_SETOPTIONS: {
-               if (data & PTRACE_O_TRACESYSGOOD)
-                       child->ptrace |= PT_TRACESYSGOOD;
-               else
-                       child->ptrace &= ~PT_TRACESYSGOOD;
-               ret = 0;
-               break;
-       }
+       case PTRACE_GETREGS:    /* Get all integer regs from the child. */
+               return copy_regset_to_user(child, &user_mn10300_native_view,
+                                          REGSET_GENERAL,
+                                          0, NR_PTREGS * sizeof(long),
+                                          (void __user *)data);
+
+       case PTRACE_SETREGS:    /* Set all integer regs in the child. */
+               return copy_regset_from_user(child, &user_mn10300_native_view,
+                                            REGSET_GENERAL,
+                                            0, NR_PTREGS * sizeof(long),
+                                            (const void __user *)data);
+
+       case PTRACE_GETFPREGS:  /* Get the child FPU state. */
+               return copy_regset_to_user(child, &user_mn10300_native_view,
+                                          REGSET_FPU,
+                                          0, sizeof(struct fpu_state_struct),
+                                          (void __user *)data);
+
+       case PTRACE_SETFPREGS:  /* Set the child FPU state. */
+               return copy_regset_from_user(child, &user_mn10300_native_view,
+                                            REGSET_FPU,
+                                            0, sizeof(struct fpu_state_struct),
+                                            (const void __user *)data);
 
        default:
-               ret = -EIO;
+               ret = ptrace_request(child, request, addr, data);
                break;
        }
 
@@ -337,43 +362,26 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 }
 
 /*
- * notification of system call entry/exit
- * - triggered by current->work.syscall_trace
+ * handle tracing of system call entry
+ * - return the revised system call number or ULONG_MAX to cause ENOSYS
  */
-asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
+asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs)
 {
-#if 0
-       /* just in case... */
-       printk(KERN_DEBUG "[%d] syscall_%lu(%lx,%lx,%lx,%lx) = %lx\n",
-              current->pid,
-              regs->orig_d0,
-              regs->a0,
-              regs->d1,
-              regs->a3,
-              regs->a2,
-              regs->d0);
-       return;
-#endif
-
-       if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
-           !test_thread_flag(TIF_SINGLESTEP))
-               return;
-       if (!(current->ptrace & PT_PTRACED))
-               return;
+       if (tracehook_report_syscall_entry(regs))
+               /* tracing decided this syscall should not happen, so
+                * We'll return a bogus call number to get an ENOSYS
+                * error, but leave the original number in
+                * regs->orig_d0
+                */
+               return ULONG_MAX;
 
-       /* the 0x80 provides a way for the tracing parent to distinguish
-          between a syscall stop and SIGTRAP delivery */
-       ptrace_notify(SIGTRAP |
-                     ((current->ptrace & PT_TRACESYSGOOD) &&
-                      !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
+       return regs->orig_d0;
+}
 
-       /*
-        * this isn't the same as continuing with a signal, but it will do
-        * for normal use.  strace only continues with a signal if the
-        * stopping signal is not SIGTRAP.  -brl
-        */
-       if (current->exit_code) {
-               send_sig(current->exit_code, current, 1);
-               current->exit_code = 0;
-       }
+/*
+ * handle tracing of system call exit
+ */
+asmlinkage void syscall_trace_exit(struct pt_regs *regs)
+{
+       tracehook_report_syscall_exit(regs, 0);
 }
index 841ca9955a1813836ef2d07d0b7dfbc03e335347..9f7572a0f5784a30d9ff16bbcfa407d10fc8a066 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/tty.h>
 #include <linux/personality.h>
 #include <linux/suspend.h>
+#include <linux/tracehook.h>
 #include <asm/cacheflush.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
@@ -511,6 +512,9 @@ static void do_signal(struct pt_regs *regs)
                         * clear the TIF_RESTORE_SIGMASK flag */
                        if (test_thread_flag(TIF_RESTORE_SIGMASK))
                                clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+                       tracehook_signal_handler(signr, &info, &ka, regs,
+                                                test_thread_flag(TIF_SINGLESTEP));
                }
 
                return;
@@ -561,4 +565,9 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
        /* deal with pending signal delivery */
        if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
                do_signal(regs);
+
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(__frame);
+       }
 }
index 789208094e985ec6a02f25c666492b5735c58bb9..7095147dcb8ba2f83bbad869b7b2e4366dd4a6a5 100644 (file)
@@ -165,24 +165,6 @@ ENTRY(itlb_aerror)
 ENTRY(dtlb_aerror)
        and     ~EPSW_NMID,epsw
        add     -4,sp
-       mov     d1,(sp)
-
-       movhu   (MMUFCR_DFC),d1                 # is it the initial valid write
-                                               # to this page?
-       and     MMUFCR_xFC_INITWR,d1
-       beq     dtlb_pagefault                  # jump if not
-
-       mov     (DPTEL),d1                      # set the dirty bit
-                                               # (don't replace with BSET!)
-       or      _PAGE_DIRTY,d1
-       mov     d1,(DPTEL)
-       mov     (sp),d1
-       add     4,sp
-       rti
-
-       ALIGN
-dtlb_pagefault:
-       mov     (sp),d1
        SAVE_ALL
        add     -4,sp                           # need to pass three params
 
index 4ea4229d765ccc0657148d4f2268931ea3d6b8f9..8007f1e6572986559789a2520603a77336c72214 100644 (file)
@@ -130,15 +130,17 @@ int cpu_check_affinity(unsigned int irq, const struct cpumask *dest)
        return cpu_dest;
 }
 
-static void cpu_set_affinity_irq(unsigned int irq, const struct cpumask *dest)
+static int cpu_set_affinity_irq(unsigned int irq, const struct cpumask *dest)
 {
        int cpu_dest;
 
        cpu_dest = cpu_check_affinity(irq, dest);
        if (cpu_dest < 0)
-               return;
+               return -1;
 
        cpumask_copy(&irq_desc[irq].affinity, dest);
+
+       return 0;
 }
 #endif
 
index 9057335fdc616ce607f76b2dc7e099965ce49e5e..2cf915e51e7e9e7c7ad6202e0d287187b8a313ed 100644 (file)
@@ -41,6 +41,12 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
        return !!(v->arch.pending_exceptions);
 }
 
+int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
+{
+       /* do real check here */
+       return 1;
+}
+
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
        return !(v->arch.msr & MSR_WE);
index 80b513449f4c44d3c98915efe233c01caa382f4d..be3581a8c294c8de4d083b1b2c5710381a35c2d9 100644 (file)
@@ -333,7 +333,7 @@ static void xics_eoi_lpar(unsigned int virq)
        lpar_xirr_info_set((0xff << 24) | irq);
 }
 
-static void xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
+static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
 {
        unsigned int irq;
        int status;
@@ -342,14 +342,14 @@ static void xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
 
        irq = (unsigned int)irq_map[virq].hwirq;
        if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
-               return;
+               return -1;
 
        status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
 
        if (status) {
                printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n",
                        __func__, irq, status);
-               return;
+               return -1;
        }
 
        /*
@@ -363,7 +363,7 @@ static void xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
                printk(KERN_WARNING
                        "%s: No online cpus in the mask %s for irq %d\n",
                        __func__, cpulist, virq);
-               return;
+               return -1;
        }
 
        status = rtas_call(ibm_set_xive, 3, 1, NULL,
@@ -372,8 +372,10 @@ static void xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
        if (status) {
                printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n",
                        __func__, irq, status);
-               return;
+               return -1;
        }
+
+       return 0;
 }
 
 static struct irq_chip xics_pic_direct = {
index 9e105cbc5e5f4c3fb3f10654485d009cb37bb111..a4779912a5caa4d45eacedd3b584d33a2537fafd 100644 (file)
@@ -250,7 +250,7 @@ axon_ram_probe(struct of_device *device, const struct of_device_id *device_id)
 
        set_capacity(bank->disk, bank->size >> AXON_RAM_SECTOR_SHIFT);
        blk_queue_make_request(bank->disk->queue, axon_ram_make_request);
-       blk_queue_hardsect_size(bank->disk->queue, AXON_RAM_SECTOR_SIZE);
+       blk_queue_logical_block_size(bank->disk->queue, AXON_RAM_SECTOR_SIZE);
        add_disk(bank->disk);
 
        bank->irq_id = irq_of_parse_and_map(device->node, 0);
index 0efc12d1a3d77f98716f500c5ca12f9f923e3e9d..352d8c3ef5269c97e548789edccc49c420214a71 100644 (file)
@@ -807,7 +807,7 @@ static void mpic_end_ipi(unsigned int irq)
 
 #endif /* CONFIG_SMP */
 
-void mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
+int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
 {
        struct mpic *mpic = mpic_from_irq(irq);
        unsigned int src = mpic_irq_to_hw(irq);
@@ -824,6 +824,8 @@ void mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
                mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION),
                               mpic_physmask(cpus_addr(tmp)[0]));
        }
+
+       return 0;
 }
 
 static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type)
index 3cef2af10f4254daea1ff69769117ffb1f8a23b3..eff433c322a0c55632b7d413acfddc18ed5cbaa8 100644 (file)
@@ -36,6 +36,6 @@ static inline int mpic_pasemi_msi_init(struct mpic *mpic)
 
 extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type);
 extern void mpic_set_vector(unsigned int virq, unsigned int vector);
-extern void mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask);
+extern int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask);
 
 #endif /* _POWERPC_SYSDEV_MPIC_H */
index 54ea39f96ecdf17f04a078f51a1c20d45003897b..a27d0d5a6f8689fa81f558686cad2f378487be42 100644 (file)
@@ -13,6 +13,8 @@
 
 #ifndef ASM_KVM_HOST_H
 #define ASM_KVM_HOST_H
+#include <linux/hrtimer.h>
+#include <linux/interrupt.h>
 #include <linux/kvm_host.h>
 #include <asm/debug.h>
 #include <asm/cpuid.h>
@@ -210,7 +212,8 @@ struct kvm_vcpu_arch {
        s390_fp_regs      guest_fpregs;
        unsigned int      guest_acrs[NUM_ACRS];
        struct kvm_s390_local_interrupt local_int;
-       struct timer_list ckc_timer;
+       struct hrtimer    ckc_timer;
+       struct tasklet_struct tasklet;
        union  {
                cpuid_t   cpu_id;
                u64       stidp_data;
index 9d19803111bab26d8021d3aaf2f0f028092f8c8b..98997ccba50151dbf7965831b062e5f74c44fb93 100644 (file)
@@ -154,17 +154,25 @@ static int handle_stop(struct kvm_vcpu *vcpu)
 static int handle_validity(struct kvm_vcpu *vcpu)
 {
        int viwhy = vcpu->arch.sie_block->ipb >> 16;
+       int rc;
+
        vcpu->stat.exit_validity++;
-       if (viwhy == 0x37) {
-               fault_in_pages_writeable((char __user *)
-                                        vcpu->kvm->arch.guest_origin +
-                                        vcpu->arch.sie_block->prefix,
-                                        PAGE_SIZE);
-               return 0;
-       }
-       VCPU_EVENT(vcpu, 2, "unhandled validity intercept code %d",
-                  viwhy);
-       return -ENOTSUPP;
+       if ((viwhy == 0x37) && (vcpu->arch.sie_block->prefix
+               <= vcpu->kvm->arch.guest_memsize - 2*PAGE_SIZE)){
+               rc = fault_in_pages_writeable((char __user *)
+                        vcpu->kvm->arch.guest_origin +
+                        vcpu->arch.sie_block->prefix,
+                        2*PAGE_SIZE);
+               if (rc)
+                       /* user will receive sigsegv, exit to user */
+                       rc = -ENOTSUPP;
+       } else
+               rc = -ENOTSUPP;
+
+       if (rc)
+               VCPU_EVENT(vcpu, 2, "unhandled validity intercept code %d",
+                          viwhy);
+       return rc;
 }
 
 static int handle_instruction(struct kvm_vcpu *vcpu)
index 0189356fe2098cb3f6ddd61434da623b8a7c9cfa..f04f5301b1b42fdd06207c93a84bd6568594cd72 100644 (file)
@@ -12,6 +12,8 @@
 
 #include <asm/lowcore.h>
 #include <asm/uaccess.h>
+#include <linux/hrtimer.h>
+#include <linux/interrupt.h>
 #include <linux/kvm_host.h>
 #include <linux/signal.h>
 #include "kvm-s390.h"
@@ -299,13 +301,13 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
        }
 
        if ((!rc) && atomic_read(&fi->active)) {
-               spin_lock_bh(&fi->lock);
+               spin_lock(&fi->lock);
                list_for_each_entry(inti, &fi->list, list)
                        if (__interrupt_is_deliverable(vcpu, inti)) {
                                rc = 1;
                                break;
                        }
-               spin_unlock_bh(&fi->lock);
+               spin_unlock(&fi->lock);
        }
 
        if ((!rc) && (vcpu->arch.sie_block->ckc <
@@ -318,6 +320,12 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
        return rc;
 }
 
+int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
+{
+       /* do real check here */
+       return 1;
+}
+
 int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
 {
        return 0;
@@ -355,14 +363,12 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
                return 0;
        }
 
-       sltime = (vcpu->arch.sie_block->ckc - now) / (0xf4240000ul / HZ) + 1;
+       sltime = ((vcpu->arch.sie_block->ckc - now)*125)>>9;
 
-       vcpu->arch.ckc_timer.expires = jiffies + sltime;
-
-       add_timer(&vcpu->arch.ckc_timer);
-       VCPU_EVENT(vcpu, 5, "enabled wait timer:%llx jiffies", sltime);
+       hrtimer_start(&vcpu->arch.ckc_timer, ktime_set (0, sltime) , HRTIMER_MODE_REL);
+       VCPU_EVENT(vcpu, 5, "enabled wait via clock comparator: %llx ns", sltime);
 no_timer:
-       spin_lock_bh(&vcpu->arch.local_int.float_int->lock);
+       spin_lock(&vcpu->arch.local_int.float_int->lock);
        spin_lock_bh(&vcpu->arch.local_int.lock);
        add_wait_queue(&vcpu->arch.local_int.wq, &wait);
        while (list_empty(&vcpu->arch.local_int.list) &&
@@ -371,33 +377,46 @@ no_timer:
                !signal_pending(current)) {
                set_current_state(TASK_INTERRUPTIBLE);
                spin_unlock_bh(&vcpu->arch.local_int.lock);
-               spin_unlock_bh(&vcpu->arch.local_int.float_int->lock);
+               spin_unlock(&vcpu->arch.local_int.float_int->lock);
                vcpu_put(vcpu);
                schedule();
                vcpu_load(vcpu);
-               spin_lock_bh(&vcpu->arch.local_int.float_int->lock);
+               spin_lock(&vcpu->arch.local_int.float_int->lock);
                spin_lock_bh(&vcpu->arch.local_int.lock);
        }
        __unset_cpu_idle(vcpu);
        __set_current_state(TASK_RUNNING);
        remove_wait_queue(&vcpu->wq, &wait);
        spin_unlock_bh(&vcpu->arch.local_int.lock);
-       spin_unlock_bh(&vcpu->arch.local_int.float_int->lock);
-       del_timer(&vcpu->arch.ckc_timer);
+       spin_unlock(&vcpu->arch.local_int.float_int->lock);
+       hrtimer_try_to_cancel(&vcpu->arch.ckc_timer);
        return 0;
 }
 
-void kvm_s390_idle_wakeup(unsigned long data)
+void kvm_s390_tasklet(unsigned long parm)
 {
-       struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
+       struct kvm_vcpu *vcpu = (struct kvm_vcpu *) parm;
 
-       spin_lock_bh(&vcpu->arch.local_int.lock);
+       spin_lock(&vcpu->arch.local_int.lock);
        vcpu->arch.local_int.timer_due = 1;
        if (waitqueue_active(&vcpu->arch.local_int.wq))
                wake_up_interruptible(&vcpu->arch.local_int.wq);
-       spin_unlock_bh(&vcpu->arch.local_int.lock);
+       spin_unlock(&vcpu->arch.local_int.lock);
 }
 
+/*
+ * low level hrtimer wake routine. Because this runs in hardirq context
+ * we schedule a tasklet to do the real work.
+ */
+enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer)
+{
+       struct kvm_vcpu *vcpu;
+
+       vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer);
+       tasklet_schedule(&vcpu->arch.tasklet);
+
+       return HRTIMER_NORESTART;
+}
 
 void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
 {
@@ -436,7 +455,7 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
        if (atomic_read(&fi->active)) {
                do {
                        deliver = 0;
-                       spin_lock_bh(&fi->lock);
+                       spin_lock(&fi->lock);
                        list_for_each_entry_safe(inti, n, &fi->list, list) {
                                if (__interrupt_is_deliverable(vcpu, inti)) {
                                        list_del(&inti->list);
@@ -447,7 +466,7 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
                        }
                        if (list_empty(&fi->list))
                                atomic_set(&fi->active, 0);
-                       spin_unlock_bh(&fi->lock);
+                       spin_unlock(&fi->lock);
                        if (deliver) {
                                __do_deliver_interrupt(vcpu, inti);
                                kfree(inti);
@@ -512,7 +531,7 @@ int kvm_s390_inject_vm(struct kvm *kvm,
 
        mutex_lock(&kvm->lock);
        fi = &kvm->arch.float_int;
-       spin_lock_bh(&fi->lock);
+       spin_lock(&fi->lock);
        list_add_tail(&inti->list, &fi->list);
        atomic_set(&fi->active, 1);
        sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS);
@@ -529,7 +548,7 @@ int kvm_s390_inject_vm(struct kvm *kvm,
        if (waitqueue_active(&li->wq))
                wake_up_interruptible(&li->wq);
        spin_unlock_bh(&li->lock);
-       spin_unlock_bh(&fi->lock);
+       spin_unlock(&fi->lock);
        mutex_unlock(&kvm->lock);
        return 0;
 }
index f4d56e9939c90949c1e886eaabf6cc7d35cab858..10bccd1f8aee58a33220bfbc07aa3b3452b1b3e7 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/compiler.h>
 #include <linux/err.h>
 #include <linux/fs.h>
+#include <linux/hrtimer.h>
 #include <linux/init.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
@@ -195,6 +196,10 @@ out_nokvm:
 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 {
        VCPU_EVENT(vcpu, 3, "%s", "free cpu");
+       if (vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda ==
+               (__u64) vcpu->arch.sie_block)
+               vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda = 0;
+       smp_mb();
        free_page((unsigned long)(vcpu->arch.sie_block));
        kvm_vcpu_uninit(vcpu);
        kfree(vcpu);
@@ -283,8 +288,10 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
        vcpu->arch.sie_block->gmsor = vcpu->kvm->arch.guest_origin;
        vcpu->arch.sie_block->ecb   = 2;
        vcpu->arch.sie_block->eca   = 0xC1002001U;
-       setup_timer(&vcpu->arch.ckc_timer, kvm_s390_idle_wakeup,
-                (unsigned long) vcpu);
+       hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
+       tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet,
+                    (unsigned long) vcpu);
+       vcpu->arch.ckc_timer.function = kvm_s390_idle_wakeup;
        get_cpu_id(&vcpu->arch.cpu_id);
        vcpu->arch.cpu_id.version = 0xff;
        return 0;
@@ -307,19 +314,21 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
 
        vcpu->arch.sie_block->icpua = id;
        BUG_ON(!kvm->arch.sca);
-       BUG_ON(kvm->arch.sca->cpu[id].sda);
-       kvm->arch.sca->cpu[id].sda = (__u64) vcpu->arch.sie_block;
+       if (!kvm->arch.sca->cpu[id].sda)
+               kvm->arch.sca->cpu[id].sda = (__u64) vcpu->arch.sie_block;
+       else
+               BUG_ON(!kvm->vcpus[id]); /* vcpu does already exist */
        vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32);
        vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
 
        spin_lock_init(&vcpu->arch.local_int.lock);
        INIT_LIST_HEAD(&vcpu->arch.local_int.list);
        vcpu->arch.local_int.float_int = &kvm->arch.float_int;
-       spin_lock_bh(&kvm->arch.float_int.lock);
+       spin_lock(&kvm->arch.float_int.lock);
        kvm->arch.float_int.local_int[id] = &vcpu->arch.local_int;
        init_waitqueue_head(&vcpu->arch.local_int.wq);
        vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags;
-       spin_unlock_bh(&kvm->arch.float_int.lock);
+       spin_unlock(&kvm->arch.float_int.lock);
 
        rc = kvm_vcpu_init(vcpu, kvm, id);
        if (rc)
@@ -478,6 +487,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
        vcpu_load(vcpu);
 
+       /* verify, that memory has been registered */
+       if (!vcpu->kvm->arch.guest_memsize) {
+               vcpu_put(vcpu);
+               return -EINVAL;
+       }
+
        if (vcpu->sigset_active)
                sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
 
@@ -657,6 +672,8 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
                                struct kvm_memory_slot old,
                                int user_alloc)
 {
+       int i;
+
        /* A few sanity checks. We can have exactly one memory slot which has
           to start at guest virtual zero and which has to be located at a
           page boundary in userland and which has to end at a page boundary.
@@ -664,7 +681,7 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
           vmas. It is okay to mmap() and munmap() stuff in this slot after
           doing this call at any time */
 
-       if (mem->slot)
+       if (mem->slot || kvm->arch.guest_memsize)
                return -EINVAL;
 
        if (mem->guest_phys_addr)
@@ -676,15 +693,39 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
        if (mem->memory_size & (PAGE_SIZE - 1))
                return -EINVAL;
 
+       if (!user_alloc)
+               return -EINVAL;
+
+       /* lock all vcpus */
+       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+               if (!kvm->vcpus[i])
+                       continue;
+               if (!mutex_trylock(&kvm->vcpus[i]->mutex))
+                       goto fail_out;
+       }
+
        kvm->arch.guest_origin = mem->userspace_addr;
        kvm->arch.guest_memsize = mem->memory_size;
 
-       /* FIXME: we do want to interrupt running CPUs and update their memory
-          configuration now to avoid race conditions. But hey, changing the
-          memory layout while virtual CPUs are running is usually bad
-          programming practice. */
+       /* update sie control blocks, and unlock all vcpus */
+       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+               if (kvm->vcpus[i]) {
+                       kvm->vcpus[i]->arch.sie_block->gmsor =
+                               kvm->arch.guest_origin;
+                       kvm->vcpus[i]->arch.sie_block->gmslm =
+                               kvm->arch.guest_memsize +
+                               kvm->arch.guest_origin +
+                               VIRTIODESCSPACE - 1ul;
+                       mutex_unlock(&kvm->vcpus[i]->mutex);
+               }
+       }
 
        return 0;
+
+fail_out:
+       for (; i >= 0; i--)
+               mutex_unlock(&kvm->vcpus[i]->mutex);
+       return -EINVAL;
 }
 
 void kvm_arch_flush_shadow(struct kvm *kvm)
index 00bbe69b78da97757b8da8840d0f55977a7aca8c..748fee872323f3cd996bfda466e01cd54fc8e169 100644 (file)
@@ -14,6 +14,7 @@
 #ifndef ARCH_S390_KVM_S390_H
 #define ARCH_S390_KVM_S390_H
 
+#include <linux/hrtimer.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 
@@ -41,7 +42,8 @@ static inline int __cpu_is_stopped(struct kvm_vcpu *vcpu)
 }
 
 int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
-void kvm_s390_idle_wakeup(unsigned long data);
+enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer);
+void kvm_s390_tasklet(unsigned long parm);
 void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu);
 int kvm_s390_inject_vm(struct kvm *kvm,
                struct kvm_s390_interrupt *s390int);
index 4b88834b8dd8bd4be94de20d5bf248b8f195bcd6..93ecd06e1a749fc866177c5bd5c6bcdd6ae82e81 100644 (file)
@@ -204,11 +204,11 @@ static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem)
        int cpus = 0;
        int n;
 
-       spin_lock_bh(&fi->lock);
+       spin_lock(&fi->lock);
        for (n = 0; n < KVM_MAX_VCPUS; n++)
                if (fi->local_int[n])
                        cpus++;
-       spin_unlock_bh(&fi->lock);
+       spin_unlock(&fi->lock);
 
        /* deal with other level 3 hypervisors */
        if (stsi(mem, 3, 2, 2) == -ENOSYS)
index f27dbedf086600280964164b207851c5f2f98dd2..36678835034d9f49a748f448fd943073e9974564 100644 (file)
@@ -52,7 +52,7 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
        if (cpu_addr >= KVM_MAX_VCPUS)
                return 3; /* not operational */
 
-       spin_lock_bh(&fi->lock);
+       spin_lock(&fi->lock);
        if (fi->local_int[cpu_addr] == NULL)
                rc = 3; /* not operational */
        else if (atomic_read(fi->local_int[cpu_addr]->cpuflags)
@@ -64,7 +64,7 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
                *reg |= SIGP_STAT_STOPPED;
                rc = 1; /* status stored */
        }
-       spin_unlock_bh(&fi->lock);
+       spin_unlock(&fi->lock);
 
        VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", cpu_addr, rc);
        return rc;
@@ -86,7 +86,7 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
 
        inti->type = KVM_S390_INT_EMERGENCY;
 
-       spin_lock_bh(&fi->lock);
+       spin_lock(&fi->lock);
        li = fi->local_int[cpu_addr];
        if (li == NULL) {
                rc = 3; /* not operational */
@@ -102,7 +102,7 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
        spin_unlock_bh(&li->lock);
        rc = 0; /* order accepted */
 unlock:
-       spin_unlock_bh(&fi->lock);
+       spin_unlock(&fi->lock);
        VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr);
        return rc;
 }
@@ -123,7 +123,7 @@ static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int store)
 
        inti->type = KVM_S390_SIGP_STOP;
 
-       spin_lock_bh(&fi->lock);
+       spin_lock(&fi->lock);
        li = fi->local_int[cpu_addr];
        if (li == NULL) {
                rc = 3; /* not operational */
@@ -142,7 +142,7 @@ static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int store)
        spin_unlock_bh(&li->lock);
        rc = 0; /* order accepted */
 unlock:
-       spin_unlock_bh(&fi->lock);
+       spin_unlock(&fi->lock);
        VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr);
        return rc;
 }
@@ -188,7 +188,7 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
        if (!inti)
                return 2; /* busy */
 
-       spin_lock_bh(&fi->lock);
+       spin_lock(&fi->lock);
        li = fi->local_int[cpu_addr];
 
        if ((cpu_addr >= KVM_MAX_VCPUS) || (li == NULL)) {
@@ -220,7 +220,7 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
 out_li:
        spin_unlock_bh(&li->lock);
 out_fi:
-       spin_unlock_bh(&fi->lock);
+       spin_unlock(&fi->lock);
        return rc;
 }
 
index e7390dd0283dde02275de43a88f726c36bfff47e..586cd045e2db213df61a3a9a46a3aaf2ecd08b8d 100644 (file)
@@ -15,6 +15,7 @@ config SUPERH
        select HAVE_IOREMAP_PROT if MMU
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DMA_API_DEBUG
+       select RTC_LIB
        help
          The SuperH is a RISC processor targeted for use in embedded systems
          and consumer electronics; it was also used in the Sega Dreamcast
@@ -74,14 +75,18 @@ config GENERIC_IOMAP
        bool
 
 config GENERIC_TIME
-       def_bool n
+       def_bool y
 
 config GENERIC_CLOCKEVENTS
-       def_bool n
+       def_bool y
 
 config GENERIC_CLOCKEVENTS_BROADCAST
        bool
 
+config GENERIC_CMOS_UPDATE
+       def_bool y
+       depends on SH_SH03 || SH_DREAMCAST
+
 config GENERIC_LOCKBREAK
        def_bool y
        depends on SMP && PREEMPT
@@ -112,6 +117,12 @@ config SYS_SUPPORTS_PCI
 config SYS_SUPPORTS_CMT
        bool
 
+config SYS_SUPPORTS_MTU2
+       bool
+
+config SYS_SUPPORTS_TMU
+       bool
+
 config STACKTRACE_SUPPORT
        def_bool y
 
@@ -157,13 +168,14 @@ config CPU_SH3
        bool
        select CPU_HAS_INTEVT
        select CPU_HAS_SR_RB
+       select SYS_SUPPORTS_TMU
 
 config CPU_SH4
        bool
        select CPU_HAS_INTEVT
        select CPU_HAS_SR_RB
-       select CPU_HAS_PTEA if !CPU_SH4A || CPU_SHX2
        select CPU_HAS_FPU if !CPU_SH4AL_DSP
+       select SYS_SUPPORTS_TMU
 
 config CPU_SH4A
        bool
@@ -177,6 +189,7 @@ config CPU_SH4AL_DSP
 config CPU_SH5
        bool
        select CPU_HAS_FPU
+       select SYS_SUPPORTS_TMU
 
 config CPU_SHX2
        bool
@@ -210,27 +223,32 @@ config CPU_SUBTYPE_SH7201
        bool "Support SH7201 processor"
        select CPU_SH2A
        select CPU_HAS_FPU
+       select SYS_SUPPORTS_MTU2
  
 config CPU_SUBTYPE_SH7203
        bool "Support SH7203 processor"
        select CPU_SH2A
        select CPU_HAS_FPU
        select SYS_SUPPORTS_CMT
+       select SYS_SUPPORTS_MTU2
 
 config CPU_SUBTYPE_SH7206
        bool "Support SH7206 processor"
        select CPU_SH2A
        select SYS_SUPPORTS_CMT
+       select SYS_SUPPORTS_MTU2
 
 config CPU_SUBTYPE_SH7263
        bool "Support SH7263 processor"
        select CPU_SH2A
        select CPU_HAS_FPU
        select SYS_SUPPORTS_CMT
+       select SYS_SUPPORTS_MTU2
 
 config CPU_SUBTYPE_MXG
        bool "Support MX-G processor"
        select CPU_SH2A
+       select SYS_SUPPORTS_MTU2
        help
          Select MX-G if running on an R8A03022BG part.
 
@@ -283,6 +301,7 @@ config CPU_SUBTYPE_SH7720
        bool "Support SH7720 processor"
        select CPU_SH3
        select CPU_HAS_DSP
+       select SYS_SUPPORTS_CMT
        help
          Select SH7720 if you have a SH3-DSP SH7720 CPU.
 
@@ -290,6 +309,7 @@ config CPU_SUBTYPE_SH7721
        bool "Support SH7721 processor"
        select CPU_SH3
        select CPU_HAS_DSP
+       select SYS_SUPPORTS_CMT
        help
          Select SH7721 if you have a SH3-DSP SH7721 CPU.
 
@@ -347,6 +367,16 @@ config CPU_SUBTYPE_SH7723
        help
          Select SH7723 if you have an SH-MobileR2 CPU.
 
+config CPU_SUBTYPE_SH7724
+       bool "Support SH7724 processor"
+       select CPU_SH4A
+       select CPU_SHX2
+       select ARCH_SHMOBILE
+       select ARCH_SPARSEMEM_ENABLE
+       select SYS_SUPPORTS_CMT
+       help
+         Select SH7724 if you have an SH-MobileR2R CPU.
+
 config CPU_SUBTYPE_SH7763
        bool "Support SH7763 processor"
        select CPU_SH4A
@@ -442,48 +472,26 @@ source "arch/sh/boards/Kconfig"
 
 menu "Timer and clock configuration"
 
-config SH_TMU
-       bool "TMU timer support"
-       depends on CPU_SH3 || CPU_SH4
+config SH_TIMER_TMU
+       bool "TMU timer driver"
+       depends on SYS_SUPPORTS_TMU
        default y
-       select GENERIC_TIME
-       select GENERIC_CLOCKEVENTS
        help
-         This enables the use of the TMU as the system timer.
+         This enables the build of the TMU timer driver.
 
-config SH_CMT
-       bool "CMT timer support"
-       depends on SYS_SUPPORTS_CMT && CPU_SH2
+config SH_TIMER_CMT
+       bool "CMT timer driver"
+       depends on SYS_SUPPORTS_CMT
        default y
        help
-         This enables the use of the CMT as the system timer.
+         This enables build of the CMT timer driver.
 
-#
-# Support for the new-style CMT driver. This will replace SH_CMT
-# once its other dependencies are merged.
-#
-config SH_TIMER_CMT
-       bool "CMT clockevents driver"
-       depends on SYS_SUPPORTS_CMT && !SH_CMT
-       select GENERIC_CLOCKEVENTS
-
-config SH_MTU2
-       bool "MTU2 timer support"
-       depends on CPU_SH2A
+config SH_TIMER_MTU2
+       bool "MTU2 timer driver"
+       depends on SYS_SUPPORTS_MTU2
        default y
        help
-         This enables the use of the MTU2 as the system timer.
-
-config SH_TIMER_IRQ
-       int
-       default "28" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785 || \
-                       CPU_SUBTYPE_SH7763
-       default "86" if CPU_SUBTYPE_SH7619
-       default "140" if CPU_SUBTYPE_SH7206
-       default "142" if CPU_SUBTYPE_SH7203 && SH_CMT
-       default "153" if CPU_SUBTYPE_SH7203 && SH_MTU2
-       default "238" if CPU_SUBTYPE_MXG
-       default "16"
+         This enables build of the MTU2 timer driver.
 
 config SH_PCLK_FREQ
        int "Peripheral clock frequency (in Hz)"
@@ -494,7 +502,7 @@ config SH_PCLK_FREQ
                              CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705 || \
                              CPU_SUBTYPE_SH7203 || CPU_SUBTYPE_SH7206 || \
                              CPU_SUBTYPE_SH7263 || CPU_SUBTYPE_MXG    || \
-                             CPU_SUBTYPE_SH7786
+                             CPU_SUBTYPE_SH7786 || CPU_SUBTYPE_SH7724
        default "60000000" if CPU_SUBTYPE_SH7751 || CPU_SUBTYPE_SH7751R
        default "66000000" if CPU_SUBTYPE_SH4_202
        default "50000000"
@@ -503,6 +511,13 @@ config SH_PCLK_FREQ
          This is necessary for determining the reference clock value on
          platforms lacking an RTC.
 
+config SH_CLK_CPG
+       def_bool y
+
+config SH_CLK_CPG_LEGACY
+       depends on SH_CLK_CPG
+       def_bool y if !CPU_SUBTYPE_SH7785 && !ARCH_SHMOBILE
+
 config SH_CLK_MD
        int "CPU Mode Pin Setting"
        depends on CPU_SH2
@@ -663,27 +678,54 @@ config GUSA_RB
          LLSC, this should be more efficient than the other alternative of
          disabling interrupts around the atomic sequence.
 
+config SPARSE_IRQ
+       bool "Support sparse irq numbering"
+       depends on EXPERIMENTAL
+       help
+         This enables support for sparse irqs. This is useful in general
+         as most CPUs have a fairly sparse array of IRQ vectors, which
+         the irq_desc then maps directly on to. Systems with a high
+         number of off-chip IRQs will want to treat this as
+         experimental until they have been independently verified.
+
+         If you don't know what to do here, say N.
+
 endmenu
 
 menu "Boot options"
 
 config ZERO_PAGE_OFFSET
-       hex "Zero page offset"
-       default "0x00004000" if SH_SH03
-       default "0x00010000" if PAGE_SIZE_64KB
+       hex
+       default "0x00010000" if PAGE_SIZE_64KB || SH_RTS7751R2D || \
+                               SH_7751_SOLUTION_ENGINE
+       default "0x00004000" if PAGE_SIZE_16KB || SH_SH03
        default "0x00002000" if PAGE_SIZE_8KB
        default "0x00001000"
        help
          This sets the default offset of zero page.
 
 config BOOT_LINK_OFFSET
-       hex "Link address offset for booting"
+       hex
+       default "0x00210000" if SH_SHMIN
+       default "0x00400000" if SH_CAYMAN
+       default "0x00810000" if SH_7780_SOLUTION_ENGINE
+       default "0x009e0000" if SH_TITAN
+       default "0x01800000" if SH_SDK7780
+       default "0x02000000" if SH_EDOSK7760
        default "0x00800000"
        help
          This option allows you to set the link address offset of the zImage.
          This can be useful if you are on a board which has a small amount of
          memory.
 
+config ENTRY_OFFSET
+       hex
+       default "0x00001000" if PAGE_SIZE_4KB
+       default "0x00002000" if PAGE_SIZE_8KB
+       default "0x00004000" if PAGE_SIZE_16KB
+       default "0x00010000" if PAGE_SIZE_64KB
+       default "0x00000000"
+
 config UBC_WAKEUP
        bool "Wakeup UBC on startup"
        depends on CPU_SH4 && !CPU_SH4A
index c7d704381a6d5425548751ed4874580a0e3c1ab9..cd6e3ea598d5b8d028720fb806ddb82a39b2e863 100644 (file)
@@ -76,11 +76,6 @@ config SPECULATIVE_EXECUTION
 
          If unsure, say N.
 
-config SH64_USER_MISALIGNED_FIXUP
-       def_bool y
-       prompt "Fixup misaligned loads/stores occurring in user mode"
-       depends on SUPERH64
-
 config SH64_ID2815_WORKAROUND
        bool "Include workaround for SH5-101 cut2 silicon defect ID2815"
        depends on CPU_SUBTYPE_SH5_101
@@ -101,9 +96,6 @@ config CPU_HAS_SR_RB
          See <file:Documentation/sh/register-banks.txt> for further
          information on SR.RB and register banking in the kernel in general.
 
-config CPU_HAS_PTEA
-       bool
-
 config CPU_HAS_PTEAEX
        bool
 
index 0d62681f72a092830134b0d5a80186fede6e59e0..8179cc9be9a4a343ab5af583cbfe52792067aa07 100644 (file)
@@ -38,10 +38,10 @@ config EARLY_SCIF_CONSOLE_PORT
        default "0xffe00000" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7763 || \
                                CPU_SUBTYPE_SH7722 || CPU_SUBTYPE_SH7366 || \
                                CPU_SUBTYPE_SH7343
-       default "0xffe80000" if CPU_SH4
        default "0xffea0000" if CPU_SUBTYPE_SH7785
        default "0xfffe8000" if CPU_SUBTYPE_SH7203
        default "0xfffe9800" if CPU_SUBTYPE_SH7206 || CPU_SUBTYPE_SH7263
+       default "0xffe80000" if CPU_SH4
        default "0x00000000"
 
 config EARLY_PRINTK
@@ -92,7 +92,7 @@ config 4KSTACKS
 
 config IRQSTACKS
        bool "Use separate kernel stacks when processing interrupts"
-       depends on DEBUG_KERNEL && SUPERH32
+       depends on DEBUG_KERNEL && SUPERH32 && BROKEN
        help
          If you say Y here the kernel will use separate kernel stacks
          for handling hard and soft interrupts.  This can help avoid
@@ -122,27 +122,8 @@ config SH_NO_BSS_INIT
          For all other cases, say N. If this option seems perplexing, or
          you aren't sure, say N.
 
-config MORE_COMPILE_OPTIONS
-       bool "Add any additional compile options"
-       help
-         If you want to add additional CFLAGS to the kernel build, enable this
-         option and then enter what you would like to add in the next question.
-         Note however that -g is already appended with the selection of KGDB.
-
-config COMPILE_OPTIONS
-       string "Additional compile arguments"
-       depends on MORE_COMPILE_OPTIONS
-
 config SH64_SR_WATCH
        bool "Debug: set SR.WATCH to enable hardware watchpoints and trace"
        depends on SUPERH64
 
-config POOR_MANS_STRACE
-       bool "Debug: enable rudimentary strace facility"
-       depends on SUPERH64
-       help
-         This option allows system calls to be traced to the console.  It also
-         aids in detecting kernel stack underflow.  It is useful for debugging
-         early-userland problems (e.g. init incurring fatal exceptions.)
-
 endmenu
index bece1f7535f2008c9f3199753e2241f1f73f9fb2..75d049b03f7e04231de0525ba6b57e3779fe2984 100644 (file)
@@ -70,9 +70,6 @@ cflags-$(CONFIG_CPU_LITTLE_ENDIAN)    += -ml
 cflags-y       += $(call cc-option,-mno-fdpic)
 cflags-y       += $(isaflags-y) -ffreestanding
 
-cflags-$(CONFIG_MORE_COMPILE_OPTIONS)  += \
-       $(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
-
 OBJCOPYFLAGS   := -O binary -R .note -R .note.gnu.build-id -R .comment \
                   -R .stab -R .stabstr -S
 
@@ -85,7 +82,6 @@ defaultimage-$(CONFIG_SH_7206_SOLUTION_ENGINE)        := vmlinux
 defaultimage-$(CONFIG_SH_7619_SOLUTION_ENGINE) := vmlinux
 
 # Set some sensible Kbuild defaults
-KBUILD_DEFCONFIG       := shx3_defconfig
 KBUILD_IMAGE           := $(defaultimage-y)
 
 #
@@ -93,26 +89,38 @@ KBUILD_IMAGE                := $(defaultimage-y)
 # error messages during linking.
 #
 ifdef CONFIG_SUPERH32
-UTS_MACHINE    := sh
-LDFLAGS_vmlinux        += -e _stext
+UTS_MACHINE            := sh
+BITS                   := 32
+LDFLAGS_vmlinux                += -e _stext
+KBUILD_DEFCONFIG       := shx3_defconfig
 else
-UTS_MACHINE    := sh64
-LDFLAGS_vmlinux        += --defsym phys_stext=_stext-$(CONFIG_PAGE_OFFSET) \
-                  --defsym phys_stext_shmedia=phys_stext+1 \
-                  -e phys_stext_shmedia
+UTS_MACHINE            := sh64
+BITS                   := 64
+LDFLAGS_vmlinux                += --defsym phys_stext=_stext-$(CONFIG_PAGE_OFFSET) \
+                          --defsym phys_stext_shmedia=phys_stext+1 \
+                          -e phys_stext_shmedia
+KBUILD_DEFCONFIG       := cayman_defconfig
+endif
+
+ifneq ($(SUBARCH),$(ARCH))
+  ifeq ($(CROSS_COMPILE),)
+    CROSS_COMPILE := $(call cc-cross-prefix, $(UTS_MACHINE)-linux-  $(UTS_MACHINE)-linux-gnu-  $(UTS_MACHINE)-unknown-linux-gnu-)
+  endif
 endif
 
 ifdef CONFIG_CPU_LITTLE_ENDIAN
-LDFLAGS_vmlinux                += --defsym 'jiffies=jiffies_64'
+ld-bfd                 := elf32-$(UTS_MACHINE)-linux
+LDFLAGS_vmlinux                += --defsym 'jiffies=jiffies_64' --oformat $(ld-bfd)
 LDFLAGS                        += -EL
 else
-LDFLAGS_vmlinux                += --defsym 'jiffies=jiffies_64+4'
+ld-bfd                 := elf32-$(UTS_MACHINE)big-linux
+LDFLAGS_vmlinux                += --defsym 'jiffies=jiffies_64+4' --oformat $(ld-bfd)
 LDFLAGS                        += -EB
 endif
 
-head-y                 := arch/sh/kernel/init_task.o
-head-$(CONFIG_SUPERH32)        += arch/sh/kernel/head_32.o
-head-$(CONFIG_SUPERH64)        += arch/sh/kernel/head_64.o
+export ld-bfd BITS
+
+head-y := arch/sh/kernel/init_task.o arch/sh/kernel/head_$(BITS).o
 
 core-y                         += arch/sh/kernel/ arch/sh/mm/ arch/sh/boards/
 core-$(CONFIG_SH_FPU_EMU)      += arch/sh/math-emu/
@@ -193,10 +201,11 @@ zImage uImage uImage.srec vmlinux.srec: vmlinux
 
 compressed: zImage
 
-archprepare: maketools arch/sh/lib64/syscalltab.h
+archprepare: maketools
 
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
+       $(Q)$(MAKE) $(clean)=arch/sh/kernel/vsyscall
 
 define archhelp
        @echo '* zImage                    - Compressed kernel image'
@@ -205,34 +214,4 @@ define archhelp
        @echo '  uImage.srec               - Create an S-record for U-Boot'
 endef
 
-define filechk_gen-syscalltab
-       (set -e; \
-       echo "/*"; \
-       echo " * DO NOT MODIFY."; \
-       echo " *"; \
-       echo " * This file was generated by arch/sh/Makefile"; \
-       echo " * Any changes will be reverted at build time."; \
-       echo " */"; \
-       echo ""; \
-       echo "#ifndef __SYSCALLTAB_H"; \
-       echo "#define __SYSCALLTAB_H"; \
-       echo ""; \
-       echo "#include <linux/kernel.h>"; \
-       echo ""; \
-       echo "struct syscall_info {"; \
-       echo "  const char *name;"; \
-       echo "} syscall_info_table[] = {"; \
-       sed -e '/^.*\.long /!d;s//      { "/;s/\(\([^/]*\)\/\)\{1\}.*/\2/; \
-               s/[ \t]*$$//g;s/$$/" },/;s/\("\)sys_/\1/g'; \
-       echo "};"; \
-       echo ""; \
-       echo "#define NUM_SYSCALL_INFO_ENTRIES ARRAY_SIZE(syscall_info_table)";\
-       echo ""; \
-       echo "#endif /* __SYSCALLTAB_H */" )
-endef
-
-arch/sh/lib64/syscalltab.h: arch/sh/kernel/syscalls_64.S
-       $(call filechk,gen-syscalltab)
-
-CLEAN_FILES += arch/sh/lib64/syscalltab.h \
-              include/asm-sh/machtypes.h
+CLEAN_FILES += include/asm-sh/machtypes.h
index dcc1af8a2cfe6428c00f0b4f400ffb27cb675ca1..1c91b1f565d5444bf4775439aff906e822fa5cb6 100644 (file)
@@ -46,6 +46,15 @@ config SH_7722_SOLUTION_ENGINE
          Select 7722 SolutionEngine if configuring for a Hitachi SH772
          evaluation board.
 
+config SH_7724_SOLUTION_ENGINE
+       bool "SolutionEngine7724"
+       select SOLUTION_ENGINE
+       depends on CPU_SUBTYPE_SH7724
+       select ARCH_REQUIRE_GPIOLIB
+       help
+         Select 7724 SolutionEngine if configuring for a Hitachi SH7724
+         evaluation board.
+
 config SH_7751_SOLUTION_ENGINE
        bool "SolutionEngine7751"
        select SOLUTION_ENGINE
@@ -121,7 +130,7 @@ config SH_RTS7751R2D
        bool "RTS7751R2D"
        depends on CPU_SUBTYPE_SH7751R
        select SYS_SUPPORTS_PCI
-       select IO_TRAPPED
+       select IO_TRAPPED if MMU
        help
          Select RTS7751R2D if configuring for a Renesas Technology
          Sales SH-Graphics board.
@@ -145,13 +154,13 @@ config SH_HIGHLANDER
        bool "Highlander"
        depends on CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785
        select SYS_SUPPORTS_PCI
-       select IO_TRAPPED
+       select IO_TRAPPED if MMU
 
 config SH_SH7785LCR
        bool "SH7785LCR"
        depends on CPU_SUBTYPE_SH7785
        select SYS_SUPPORTS_PCI
-       select IO_TRAPPED
+       select IO_TRAPPED if MMU
 
 config SH_SH7785LCR_29BIT_PHYSMAPS
        bool "SH7785LCR 29bit physmaps"
index f2a29641b6a326cc857c8334383717dffc70aba7..1c4d83ef2a4724e10da98bd42d58941d4a03ba15 100644 (file)
@@ -535,6 +535,18 @@ static int __init ap325rxa_devices_setup(void)
 }
 device_initcall(ap325rxa_devices_setup);
 
+/* Return the board specific boot mode pin configuration */
+static int ap325rxa_mode_pins(void)
+{
+       /* MD0=0, MD1=0, MD2=0: Clock Mode 0
+        * MD3=0: 16-bit Area0 Bus Width
+        * MD5=1: Little Endian
+        * TSTMD=1, MD8=1: Test Mode Disabled
+        */
+       return MODE_PIN5 | MODE_PIN8;
+}
+
 static struct sh_machine_vector mv_ap325rxa __initmv = {
        .mv_name = "AP-325RXA",
+       .mv_mode_pins = ap325rxa_mode_pins,
 };
index 6f94f17adc467dd00d13aaa20ef5891b2ee064ed..7be56fb06c1f0a7aecbd95ee47f0fa805535518e 100644 (file)
@@ -2,12 +2,12 @@
  * Renesas Technology Corp. R0P7785LC0011RL Support.
  *
  * Copyright (C) 2008  Yoshihiro Shimoda
+ * Copyright (C) 2009  Paul Mundt
  *
  * 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.
  */
-
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/sm501.h>
 #include <linux/i2c-pca-platform.h>
 #include <linux/i2c-algo-pca.h>
 #include <linux/irq.h>
-#include <asm/heartbeat.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
 #include <mach/sh7785lcr.h>
+#include <asm/heartbeat.h>
+#include <asm/clock.h>
+#include <cpu/sh7785.h>
 
 /*
  * NOTE: This board has 2 physical memory maps.
@@ -273,6 +277,20 @@ void __init init_sh7785lcr_IRQ(void)
        plat_irq_setup_pins(IRQ_MODE_IRQ3210);
 }
 
+static int sh7785lcr_clk_init(void)
+{
+       struct clk *clk;
+       int ret;
+
+       clk = clk_get(NULL, "extal");
+       if (!clk || IS_ERR(clk))
+               return PTR_ERR(clk);
+       ret = clk_set_rate(clk, 33333333);
+       clk_put(clk);
+
+       return ret;
+}
+
 static void sh7785lcr_power_off(void)
 {
        unsigned char *p;
@@ -303,12 +321,34 @@ static void __init sh7785lcr_setup(char **cmdline_p)
        writel(0x000307c2, sm501_reg);
 }
 
+/* Return the board specific boot mode pin configuration */
+static int sh7785lcr_mode_pins(void)
+{
+       int value = 0;
+
+       /* These are the factory default settings of S1 and S2.
+        * If you change these dip switches then you will need to
+        * adjust the values below as well.
+        */
+       value |= MODE_PIN4; /* Clock Mode 16 */
+       value |= MODE_PIN5; /* 32-bit Area0 bus width */
+       value |= MODE_PIN6; /* 32-bit Area0 bus width */
+       value |= MODE_PIN7; /* Area 0 SRAM interface [fixed] */
+       value |= MODE_PIN8; /* Little Endian */
+       value |= MODE_PIN9; /* Master Mode */
+       value |= MODE_PIN14; /* No PLL step-up */
+
+       return value;
+}
+
 /*
  * The Machine Vector
  */
 static struct sh_machine_vector mv_sh7785lcr __initmv = {
        .mv_name                = "SH7785LCR",
        .mv_setup               = sh7785lcr_setup,
+       .mv_clk_init            = sh7785lcr_clk_init,
        .mv_init_irq            = init_sh7785lcr_IRQ,
+       .mv_mode_pins           = sh7785lcr_mode_pins,
 };
 
index cafe1ac3b29c288570e0ac5cd14743b35174e7fe..00fa3eaecb1be7a5e8bcad1ea3bb850095a0149c 100644 (file)
@@ -1,4 +1,4 @@
 #
 # Makefile for the Hitachi Cayman specific parts of the kernel
 #
-obj-y := setup.o irq.o
+obj-y := setup.o irq.o panic.o
index da62ad516994bc74aecd4823502d682c21ee5660..33f77085631937fef9d1489590980016dd0f2d15 100644 (file)
@@ -142,26 +142,11 @@ int cayman_irq_demux(int evt)
        return irq;
 }
 
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
-int cayman_irq_describe(char* p, int irq)
-{
-       if (irq < NR_INTC_IRQS) {
-               return intc_irq_describe(p, irq);
-       } else if (irq < NR_INTC_IRQS + 8) {
-               return sprintf(p, "(SMSC %d)", irq - NR_INTC_IRQS);
-       } else if ((irq >= NR_INTC_IRQS + 24) && (irq < NR_INTC_IRQS + 32)) {
-               return sprintf(p, "(PCI2 %d)", irq - (NR_INTC_IRQS + 24));
-       }
-
-       return 0;
-}
-#endif
-
 void init_cayman_irq(void)
 {
        int i;
 
-       epld_virt = onchip_remap(EPLD_BASE, 1024, "EPLD");
+       epld_virt = (unsigned long)ioremap_nocache(EPLD_BASE, 1024);
        if (!epld_virt) {
                printk(KERN_ERR "Cayman IRQ: Unable to remap EPLD\n");
                return;
diff --git a/arch/sh/boards/mach-cayman/panic.c b/arch/sh/boards/mach-cayman/panic.c
new file mode 100644 (file)
index 0000000..d1e6730
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2003  Richard Curnow, SuperH UK Limited
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <cpu/registers.h>
+
+/* THIS IS A PHYSICAL ADDRESS */
+#define HDSP2534_ADDR (0x04002100)
+
+static void poor_mans_delay(void)
+{
+       int i;
+
+       for (i = 0; i < 2500000; i++)
+               cpu_relax();
+}
+
+static void show_value(unsigned long x)
+{
+       int i;
+       unsigned nibble;
+       for (i = 0; i < 8; i++) {
+               nibble = ((x >> (i * 4)) & 0xf);
+
+               __raw_writeb(nibble + ((nibble > 9) ? 55 : 48),
+                         HDSP2534_ADDR + 0xe0 + ((7 - i) << 2));
+       }
+}
+
+void
+panic_handler(unsigned long panicPC, unsigned long panicSSR,
+             unsigned long panicEXPEVT)
+{
+       while (1) {
+               /* This piece of code displays the PC on the LED display */
+               show_value(panicPC);
+               poor_mans_delay();
+               show_value(panicSSR);
+               poor_mans_delay();
+               show_value(panicEXPEVT);
+               poor_mans_delay();
+       }
+}
index e7f9cc5f2ff11e7d350dbb067d412d4b39089fbd..7e8216ac31bda3cf263faad31ab3105e7afd0b0f 100644 (file)
@@ -102,7 +102,7 @@ static int __init smsc_superio_setup(void)
 {
        unsigned char devid, devrev;
 
-       smsc_superio_virt = onchip_remap(SMSC_SUPERIO_BASE, 1024, "SMSC SuperIO");
+       smsc_superio_virt = (unsigned long)ioremap_nocache(SMSC_SUPERIO_BASE, 1024);
        if (!smsc_superio_virt) {
                panic("Unable to remap SMSC SuperIO\n");
        }
index d1bee4884cd667da313e0105e490cd2b5a5e6750..ebe99227d4e6674704b96e4c03c7e699401b6194 100644 (file)
@@ -30,7 +30,6 @@
 
 extern struct irq_chip systemasic_int;
 extern void aica_time_init(void);
-extern int gapspci_init(void);
 extern int systemasic_irq_demux(int);
 
 static void __init dreamcast_setup(char **cmdline_p)
@@ -51,11 +50,6 @@ static void __init dreamcast_setup(char **cmdline_p)
                                         handle_level_irq);
 
        board_time_init = aica_time_init;
-
-#ifdef CONFIG_PCI
-       if (gapspci_init() < 0)
-               printk(KERN_WARNING "GAPSPCI was not detected.\n");
-#endif
 }
 
 static struct sh_machine_vector mv_dreamcast __initmv = {
index 1ee1de0bc1c3c93ab627a34ddb4acec3409f94f7..6ed401cd3156af429569bf197c99fc1cbfe861e6 100644 (file)
@@ -584,3 +584,22 @@ static int __init migor_devices_setup(void)
        return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices));
 }
 __initcall(migor_devices_setup);
+
+/* Return the board specific boot mode pin configuration */
+static int migor_mode_pins(void)
+{
+       /* MD0=1, MD1=1, MD2=0: Clock Mode 3
+        * MD3=0: 16-bit Area0 Bus Width
+        * MD5=1: Little Endian
+        * TSTMD=1, MD8=0: Test Mode Disabled
+        */
+       return MODE_PIN0 | MODE_PIN1 | MODE_PIN5;
+}
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_migor __initmv = {
+       .mv_name                = "Migo-R",
+       .mv_mode_pins           = migor_mode_pins,
+};
index c585be00956ea9a8d541656081ac80a2f86ae3f4..a625ecb93e47ee55a6300c87986c17445ad9f0a3 100644 (file)
@@ -10,6 +10,9 @@
  */
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
 #include <linux/ata_platform.h>
 #include <linux/sm501.h>
 #include <linux/sm501-regs.h>
@@ -181,6 +184,50 @@ static struct platform_device sm501_device = {
        .resource       = sm501_resources,
 };
 
+static struct mtd_partition r2d_partitions[] = {
+       {
+               .name           = "U-Boot",
+               .offset         = 0x00000000,
+               .size           = 0x00040000,
+               .mask_flags     = MTD_WRITEABLE,
+       }, {
+               .name           = "Environment",
+               .offset         = MTDPART_OFS_NXTBLK,
+               .size           = 0x00040000,
+               .mask_flags     = MTD_WRITEABLE,
+       }, {
+               .name           = "Kernel",
+               .offset         = MTDPART_OFS_NXTBLK,
+               .size           = 0x001c0000,
+       }, {
+               .name           = "Flash_FS",
+               .offset         = MTDPART_OFS_NXTBLK,
+               .size           = MTDPART_SIZ_FULL,
+       }
+};
+
+static struct physmap_flash_data flash_data = {
+       .width          = 2,
+       .nr_parts       = ARRAY_SIZE(r2d_partitions),
+       .parts          = r2d_partitions,
+};
+
+static struct resource flash_resource = {
+       .start          = 0x00000000,
+       .end            = 0x02000000,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device flash_device = {
+       .name           = "physmap-flash",
+       .id             = -1,
+       .resource       = &flash_resource,
+       .num_resources  = 1,
+       .dev            = {
+               .platform_data = &flash_data,
+       },
+};
+
 static struct platform_device *rts7751r2d_devices[] __initdata = {
        &sm501_device,
        &heartbeat_device,
@@ -203,6 +250,9 @@ static int __init rts7751r2d_devices_setup(void)
        if (register_trapped_io(&cf_trapped_io) == 0)
                platform_device_register(&cf_ide_device);
 
+       if (mach_is_r2d_plus())
+               platform_device_register(&flash_device);
+
        spi_register_board_info(spi_bus, ARRAY_SIZE(spi_bus));
 
        return platform_add_devices(rts7751r2d_devices,
diff --git a/arch/sh/boards/mach-se/7724/Makefile b/arch/sh/boards/mach-se/7724/Makefile
new file mode 100644 (file)
index 0000000..349cbd6
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the HITACHI UL SolutionEngine 7724 specific parts of the kernel
+#
+# 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.
+#
+#
+
+obj-y   := setup.o irq.o
\ No newline at end of file
diff --git a/arch/sh/boards/mach-se/7724/irq.c b/arch/sh/boards/mach-se/7724/irq.c
new file mode 100644 (file)
index 0000000..f76cf3b
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * linux/arch/sh/boards/se/7724/irq.c
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ *
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on  linux/arch/sh/boards/se/7722/irq.c
+ * Copyright (C) 2007  Nobuhiro Iwamatsu
+ *
+ * Hitachi UL SolutionEngine 7724 Support.
+ *
+ * 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.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <mach-se/mach/se7724.h>
+
+struct fpga_irq {
+       unsigned long  sraddr;
+       unsigned long  mraddr;
+       unsigned short mask;
+       unsigned int   base;
+};
+
+static unsigned int fpga2irq(unsigned int irq)
+{
+       if (irq >= IRQ0_BASE &&
+           irq <= IRQ0_END)
+               return IRQ0_IRQ;
+       else if (irq >= IRQ1_BASE &&
+                irq <= IRQ1_END)
+               return IRQ1_IRQ;
+       else
+               return IRQ2_IRQ;
+}
+
+static struct fpga_irq get_fpga_irq(unsigned int irq)
+{
+       struct fpga_irq set;
+
+       switch (irq) {
+       case IRQ0_IRQ:
+               set.sraddr = IRQ0_SR;
+               set.mraddr = IRQ0_MR;
+               set.mask   = IRQ0_MASK;
+               set.base   = IRQ0_BASE;
+               break;
+       case IRQ1_IRQ:
+               set.sraddr = IRQ1_SR;
+               set.mraddr = IRQ1_MR;
+               set.mask   = IRQ1_MASK;
+               set.base   = IRQ1_BASE;
+               break;
+       default:
+               set.sraddr = IRQ2_SR;
+               set.mraddr = IRQ2_MR;
+               set.mask   = IRQ2_MASK;
+               set.base   = IRQ2_BASE;
+               break;
+       }
+
+       return set;
+}
+
+static void disable_se7724_irq(unsigned int irq)
+{
+       struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
+       unsigned int bit = irq - set.base;
+       ctrl_outw(ctrl_inw(set.mraddr) | 0x0001 << bit, set.mraddr);
+}
+
+static void enable_se7724_irq(unsigned int irq)
+{
+       struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
+       unsigned int bit = irq - set.base;
+       ctrl_outw(ctrl_inw(set.mraddr) & ~(0x0001 << bit), set.mraddr);
+}
+
+static struct irq_chip se7724_irq_chip __read_mostly = {
+       .name           = "SE7724-FPGA",
+       .mask           = disable_se7724_irq,
+       .unmask         = enable_se7724_irq,
+       .mask_ack       = disable_se7724_irq,
+};
+
+static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+       struct fpga_irq set = get_fpga_irq(irq);
+       unsigned short intv = ctrl_inw(set.sraddr);
+       struct irq_desc *ext_desc;
+       unsigned int ext_irq = set.base;
+
+       intv &= set.mask;
+
+       while (intv) {
+               if (intv & 0x0001) {
+                       ext_desc = irq_desc + ext_irq;
+                       handle_level_irq(ext_irq, ext_desc);
+               }
+               intv >>= 1;
+               ext_irq++;
+       }
+}
+
+/*
+ * Initialize IRQ setting
+ */
+void __init init_se7724_IRQ(void)
+{
+       int i;
+
+       ctrl_outw(0xffff, IRQ0_MR);  /* mask all */
+       ctrl_outw(0xffff, IRQ1_MR);  /* mask all */
+       ctrl_outw(0xffff, IRQ2_MR);  /* mask all */
+       ctrl_outw(0x0000, IRQ0_SR);  /* clear irq */
+       ctrl_outw(0x0000, IRQ1_SR);  /* clear irq */
+       ctrl_outw(0x0000, IRQ2_SR);  /* clear irq */
+       ctrl_outw(0x002a, IRQ_MODE); /* set irq type */
+
+       for (i = 0; i < SE7724_FPGA_IRQ_NR; i++)
+               set_irq_chip_and_handler_name(SE7724_FPGA_IRQ_BASE + i,
+                                             &se7724_irq_chip,
+                                             handle_level_irq, "level");
+
+       set_irq_chained_handler(IRQ0_IRQ, se7724_irq_demux);
+       set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
+
+       set_irq_chained_handler(IRQ1_IRQ, se7724_irq_demux);
+       set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
+
+       set_irq_chained_handler(IRQ2_IRQ, se7724_irq_demux);
+       set_irq_type(IRQ2_IRQ, IRQ_TYPE_LEVEL_LOW);
+}
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
new file mode 100644 (file)
index 0000000..9cd04bd
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ * linux/arch/sh/boards/se/7724/setup.c
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ *
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/delay.h>
+#include <linux/smc91x.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <video/sh_mobile_lcdc.h>
+#include <media/sh_mobile_ceu.h>
+#include <asm/io.h>
+#include <asm/heartbeat.h>
+#include <asm/sh_keysc.h>
+#include <cpu/sh7724.h>
+#include <mach-se/mach/se7724.h>
+
+/*
+ * SWx    1234 5678
+ * ------------------------------------
+ * SW31 : 1001 1100    : default
+ * SW32 : 0111 1111    : use on board flash
+ *
+ * SW41 : abxx xxxx  -> a = 0 : Analog  monitor
+ *                          1 : Digital monitor
+ *                      b = 0 : VGA
+ *                          1 : SVGA
+ */
+
+/* Heartbeat */
+static struct heartbeat_data heartbeat_data = {
+       .regsize = 16,
+};
+
+static struct resource heartbeat_resources[] = {
+       [0] = {
+               .start  = PA_LED,
+               .end    = PA_LED,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device heartbeat_device = {
+       .name           = "heartbeat",
+       .id             = -1,
+       .dev = {
+               .platform_data = &heartbeat_data,
+       },
+       .num_resources  = ARRAY_SIZE(heartbeat_resources),
+       .resource       = heartbeat_resources,
+};
+
+/* LAN91C111 */
+static struct smc91x_platdata smc91x_info = {
+       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+};
+
+static struct resource smc91x_eth_resources[] = {
+       [0] = {
+               .name   = "SMC91C111" ,
+               .start  = 0x1a300300,
+               .end    = 0x1a30030f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ0_SMC,
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+       },
+};
+
+static struct platform_device smc91x_eth_device = {
+       .name   = "smc91x",
+       .num_resources  = ARRAY_SIZE(smc91x_eth_resources),
+       .resource       = smc91x_eth_resources,
+       .dev    = {
+               .platform_data  = &smc91x_info,
+       },
+};
+
+/* MTD */
+static struct mtd_partition nor_flash_partitions[] = {
+       {
+               .name = "uboot",
+               .offset = 0,
+               .size = (1 * 1024 * 1024),
+               .mask_flags = MTD_WRITEABLE,    /* Read-only */
+       }, {
+               .name = "kernel",
+               .offset = MTDPART_OFS_APPEND,
+               .size = (2 * 1024 * 1024),
+       }, {
+               .name = "free-area",
+               .offset = MTDPART_OFS_APPEND,
+               .size = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct physmap_flash_data nor_flash_data = {
+       .width          = 2,
+       .parts          = nor_flash_partitions,
+       .nr_parts       = ARRAY_SIZE(nor_flash_partitions),
+};
+
+static struct resource nor_flash_resources[] = {
+       [0] = {
+               .name   = "NOR Flash",
+               .start  = 0x00000000,
+               .end    = 0x01ffffff,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
+static struct platform_device nor_flash_device = {
+       .name           = "physmap-flash",
+       .resource       = nor_flash_resources,
+       .num_resources  = ARRAY_SIZE(nor_flash_resources),
+       .dev            = {
+               .platform_data = &nor_flash_data,
+       },
+};
+
+/* LCDC */
+static struct sh_mobile_lcdc_info lcdc_info = {
+       .clock_source = LCDC_CLK_EXTERNAL,
+       .ch[0] = {
+               .chan = LCDC_CHAN_MAINLCD,
+               .bpp = 16,
+               .clock_divider = 1,
+               .lcd_cfg = {
+                       .name = "LB070WV1",
+                       .sync = 0, /* hsync and vsync are active low */
+               },
+               .lcd_size_cfg = { /* 7.0 inch */
+                       .width = 152,
+                       .height = 91,
+               },
+               .board_cfg = {
+               },
+       }
+};
+
+static struct resource lcdc_resources[] = {
+       [0] = {
+               .name   = "LCDC",
+               .start  = 0xfe940000,
+               .end    = 0xfe941fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 106,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device lcdc_device = {
+       .name           = "sh_mobile_lcdc_fb",
+       .num_resources  = ARRAY_SIZE(lcdc_resources),
+       .resource       = lcdc_resources,
+       .dev            = {
+               .platform_data  = &lcdc_info,
+       },
+};
+
+/* CEU0 */
+static struct sh_mobile_ceu_info sh_mobile_ceu0_info = {
+       .flags = SH_CEU_FLAG_USE_8BIT_BUS,
+};
+
+static struct resource ceu0_resources[] = {
+       [0] = {
+               .name   = "CEU0",
+               .start  = 0xfe910000,
+               .end    = 0xfe91009f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 52,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               /* place holder for contiguous memory */
+       },
+};
+
+static struct platform_device ceu0_device = {
+       .name           = "sh_mobile_ceu",
+       .id             = 0, /* "ceu0" clock */
+       .num_resources  = ARRAY_SIZE(ceu0_resources),
+       .resource       = ceu0_resources,
+       .dev    = {
+               .platform_data  = &sh_mobile_ceu0_info,
+       },
+};
+
+/* CEU1 */
+static struct sh_mobile_ceu_info sh_mobile_ceu1_info = {
+       .flags = SH_CEU_FLAG_USE_8BIT_BUS,
+};
+
+static struct resource ceu1_resources[] = {
+       [0] = {
+               .name   = "CEU1",
+               .start  = 0xfe914000,
+               .end    = 0xfe91409f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 63,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               /* place holder for contiguous memory */
+       },
+};
+
+static struct platform_device ceu1_device = {
+       .name           = "sh_mobile_ceu",
+       .id             = 1, /* "ceu1" clock */
+       .num_resources  = ARRAY_SIZE(ceu1_resources),
+       .resource       = ceu1_resources,
+       .dev    = {
+               .platform_data  = &sh_mobile_ceu1_info,
+       },
+};
+
+/* KEYSC */
+static struct sh_keysc_info keysc_info = {
+       .mode = SH_KEYSC_MODE_1,
+       .scan_timing = 10,
+       .delay = 50,
+       .keycodes = {
+               KEY_1, KEY_2, KEY_3, KEY_4, KEY_5,
+               KEY_6, KEY_7, KEY_8, KEY_9, KEY_A,
+               KEY_B, KEY_C, KEY_D, KEY_E, KEY_F,
+               KEY_G, KEY_H, KEY_I, KEY_K, KEY_L,
+               KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q,
+               KEY_R, KEY_S, KEY_T, KEY_U, KEY_V,
+       },
+};
+
+static struct resource keysc_resources[] = {
+       [0] = {
+               .start  = 0x1a204000,
+               .end    = 0x1a20400f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ0_KEY,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device keysc_device = {
+       .name           = "sh_keysc",
+       .id             = 0, /* "keysc0" clock */
+       .num_resources  = ARRAY_SIZE(keysc_resources),
+       .resource       = keysc_resources,
+       .dev    = {
+               .platform_data  = &keysc_info,
+       },
+};
+
+static struct platform_device *ms7724se_devices[] __initdata = {
+       &heartbeat_device,
+       &smc91x_eth_device,
+       &lcdc_device,
+       &nor_flash_device,
+       &ceu0_device,
+       &ceu1_device,
+       &keysc_device,
+};
+
+#define SW4140    0xBA201000
+#define FPGA_OUT  0xBA200400
+#define PORT_HIZA 0xA4050158
+
+#define SW41_A    0x0100
+#define SW41_B    0x0200
+#define SW41_C    0x0400
+#define SW41_D    0x0800
+#define SW41_E    0x1000
+#define SW41_F    0x2000
+#define SW41_G    0x4000
+#define SW41_H    0x8000
+static int __init devices_setup(void)
+{
+       u16 sw = ctrl_inw(SW4140); /* select camera, monitor */
+
+       /* Reset Release */
+       ctrl_outw(ctrl_inw(FPGA_OUT) &
+                 ~((1 << 1)  | /* LAN */
+                   (1 << 6)  | /* VIDEO DAC */
+                   (1 << 12)), /* USB0 */
+                 FPGA_OUT);
+
+       /* enable IRQ 0,1,2 */
+       gpio_request(GPIO_FN_INTC_IRQ0, NULL);
+       gpio_request(GPIO_FN_INTC_IRQ1, NULL);
+       gpio_request(GPIO_FN_INTC_IRQ2, NULL);
+
+       /* enable SCIFA3 */
+       gpio_request(GPIO_FN_SCIF3_I_SCK, NULL);
+       gpio_request(GPIO_FN_SCIF3_I_RXD, NULL);
+       gpio_request(GPIO_FN_SCIF3_I_TXD, NULL);
+       gpio_request(GPIO_FN_SCIF3_I_CTS, NULL);
+       gpio_request(GPIO_FN_SCIF3_I_RTS, NULL);
+
+       /* enable LCDC */
+       gpio_request(GPIO_FN_LCDD23,   NULL);
+       gpio_request(GPIO_FN_LCDD22,   NULL);
+       gpio_request(GPIO_FN_LCDD21,   NULL);
+       gpio_request(GPIO_FN_LCDD20,   NULL);
+       gpio_request(GPIO_FN_LCDD19,   NULL);
+       gpio_request(GPIO_FN_LCDD18,   NULL);
+       gpio_request(GPIO_FN_LCDD17,   NULL);
+       gpio_request(GPIO_FN_LCDD16,   NULL);
+       gpio_request(GPIO_FN_LCDD15,   NULL);
+       gpio_request(GPIO_FN_LCDD14,   NULL);
+       gpio_request(GPIO_FN_LCDD13,   NULL);
+       gpio_request(GPIO_FN_LCDD12,   NULL);
+       gpio_request(GPIO_FN_LCDD11,   NULL);
+       gpio_request(GPIO_FN_LCDD10,   NULL);
+       gpio_request(GPIO_FN_LCDD9,    NULL);
+       gpio_request(GPIO_FN_LCDD8,    NULL);
+       gpio_request(GPIO_FN_LCDD7,    NULL);
+       gpio_request(GPIO_FN_LCDD6,    NULL);
+       gpio_request(GPIO_FN_LCDD5,    NULL);
+       gpio_request(GPIO_FN_LCDD4,    NULL);
+       gpio_request(GPIO_FN_LCDD3,    NULL);
+       gpio_request(GPIO_FN_LCDD2,    NULL);
+       gpio_request(GPIO_FN_LCDD1,    NULL);
+       gpio_request(GPIO_FN_LCDD0,    NULL);
+       gpio_request(GPIO_FN_LCDDISP,  NULL);
+       gpio_request(GPIO_FN_LCDHSYN,  NULL);
+       gpio_request(GPIO_FN_LCDDCK,   NULL);
+       gpio_request(GPIO_FN_LCDVSYN,  NULL);
+       gpio_request(GPIO_FN_LCDDON,   NULL);
+       gpio_request(GPIO_FN_LCDVEPWC, NULL);
+       gpio_request(GPIO_FN_LCDVCPWC, NULL);
+       gpio_request(GPIO_FN_LCDRD,    NULL);
+       gpio_request(GPIO_FN_LCDLCLK,  NULL);
+       ctrl_outw((ctrl_inw(PORT_HIZA) & ~0x0001), PORT_HIZA);
+
+       /* enable CEU0 */
+       gpio_request(GPIO_FN_VIO0_D15, NULL);
+       gpio_request(GPIO_FN_VIO0_D14, NULL);
+       gpio_request(GPIO_FN_VIO0_D13, NULL);
+       gpio_request(GPIO_FN_VIO0_D12, NULL);
+       gpio_request(GPIO_FN_VIO0_D11, NULL);
+       gpio_request(GPIO_FN_VIO0_D10, NULL);
+       gpio_request(GPIO_FN_VIO0_D9,  NULL);
+       gpio_request(GPIO_FN_VIO0_D8,  NULL);
+       gpio_request(GPIO_FN_VIO0_D7,  NULL);
+       gpio_request(GPIO_FN_VIO0_D6,  NULL);
+       gpio_request(GPIO_FN_VIO0_D5,  NULL);
+       gpio_request(GPIO_FN_VIO0_D4,  NULL);
+       gpio_request(GPIO_FN_VIO0_D3,  NULL);
+       gpio_request(GPIO_FN_VIO0_D2,  NULL);
+       gpio_request(GPIO_FN_VIO0_D1,  NULL);
+       gpio_request(GPIO_FN_VIO0_D0,  NULL);
+       gpio_request(GPIO_FN_VIO0_VD,  NULL);
+       gpio_request(GPIO_FN_VIO0_CLK, NULL);
+       gpio_request(GPIO_FN_VIO0_FLD, NULL);
+       gpio_request(GPIO_FN_VIO0_HD,  NULL);
+       platform_resource_setup_memory(&ceu0_device, "ceu", 4 << 20);
+
+       /* enable CEU1 */
+       gpio_request(GPIO_FN_VIO1_D7,  NULL);
+       gpio_request(GPIO_FN_VIO1_D6,  NULL);
+       gpio_request(GPIO_FN_VIO1_D5,  NULL);
+       gpio_request(GPIO_FN_VIO1_D4,  NULL);
+       gpio_request(GPIO_FN_VIO1_D3,  NULL);
+       gpio_request(GPIO_FN_VIO1_D2,  NULL);
+       gpio_request(GPIO_FN_VIO1_D1,  NULL);
+       gpio_request(GPIO_FN_VIO1_D0,  NULL);
+       gpio_request(GPIO_FN_VIO1_FLD, NULL);
+       gpio_request(GPIO_FN_VIO1_HD,  NULL);
+       gpio_request(GPIO_FN_VIO1_VD,  NULL);
+       gpio_request(GPIO_FN_VIO1_CLK, NULL);
+       platform_resource_setup_memory(&ceu1_device, "ceu", 4 << 20);
+
+       /* KEYSC */
+       gpio_request(GPIO_FN_KEYOUT5_IN5, NULL);
+       gpio_request(GPIO_FN_KEYOUT4_IN6, NULL);
+       gpio_request(GPIO_FN_KEYIN4,      NULL);
+       gpio_request(GPIO_FN_KEYIN3,      NULL);
+       gpio_request(GPIO_FN_KEYIN2,      NULL);
+       gpio_request(GPIO_FN_KEYIN1,      NULL);
+       gpio_request(GPIO_FN_KEYIN0,      NULL);
+       gpio_request(GPIO_FN_KEYOUT3,     NULL);
+       gpio_request(GPIO_FN_KEYOUT2,     NULL);
+       gpio_request(GPIO_FN_KEYOUT1,     NULL);
+       gpio_request(GPIO_FN_KEYOUT0,     NULL);
+
+       if (sw & SW41_B) {
+               /* SVGA */
+               lcdc_info.ch[0].lcd_cfg.xres         = 800;
+               lcdc_info.ch[0].lcd_cfg.yres         = 600;
+               lcdc_info.ch[0].lcd_cfg.left_margin  = 142;
+               lcdc_info.ch[0].lcd_cfg.right_margin = 52;
+               lcdc_info.ch[0].lcd_cfg.hsync_len    = 96;
+               lcdc_info.ch[0].lcd_cfg.upper_margin = 24;
+               lcdc_info.ch[0].lcd_cfg.lower_margin = 2;
+               lcdc_info.ch[0].lcd_cfg.vsync_len    = 2;
+       } else {
+               /* VGA */
+               lcdc_info.ch[0].lcd_cfg.xres         = 640;
+               lcdc_info.ch[0].lcd_cfg.yres         = 480;
+               lcdc_info.ch[0].lcd_cfg.left_margin  = 105;
+               lcdc_info.ch[0].lcd_cfg.right_margin = 50;
+               lcdc_info.ch[0].lcd_cfg.hsync_len    = 96;
+               lcdc_info.ch[0].lcd_cfg.upper_margin = 33;
+               lcdc_info.ch[0].lcd_cfg.lower_margin = 10;
+               lcdc_info.ch[0].lcd_cfg.vsync_len    = 2;
+       }
+
+       if (sw & SW41_A) {
+               /* Digital monitor */
+               lcdc_info.ch[0].interface_type = RGB18;
+               lcdc_info.ch[0].flags          = 0;
+       } else {
+               /* Analog monitor */
+               lcdc_info.ch[0].interface_type = RGB24;
+               lcdc_info.ch[0].flags          = LCDC_FLAGS_DWPOL;
+       }
+
+       return platform_add_devices(ms7724se_devices,
+                               ARRAY_SIZE(ms7724se_devices));
+}
+device_initcall(devices_setup);
+
+static struct sh_machine_vector mv_ms7724se __initmv = {
+       .mv_name        = "ms7724se",
+       .mv_init_irq    = init_se7724_IRQ,
+       .mv_nr_irqs     = SE7724_FPGA_IRQ_BASE + SE7724_FPGA_IRQ_NR,
+};
index dbc29f3a9de50be179088eb1f1e69f5fb9fc2cfe..e6f4341bfe6eaa0467e60dfb56ae08688ea5a9c0 100644 (file)
@@ -3,5 +3,3 @@
 #
 
 obj-y   := setup.o io.o irq.o
-
-obj-$(CONFIG_PCI) += pci.o
index 6287ae570319c53519def0363557b1d53136e042..6e75bd4459e5c766c88bd6a2869a2b01f22b898f 100644 (file)
@@ -34,8 +34,6 @@ unsigned char sh7751se_inb(unsigned long port)
 {
        if (PXSEG(port))
                return *(volatile unsigned char *)port;
-       else if (is_pci_ioaddr(port))
-               return *(volatile unsigned char *)pci_ioaddr(port);
        else
                return (*port2adr(port)) & 0xff;
 }
@@ -46,8 +44,6 @@ unsigned char sh7751se_inb_p(unsigned long port)
 
         if (PXSEG(port))
                 v = *(volatile unsigned char *)port;
-       else if (is_pci_ioaddr(port))
-                v = *(volatile unsigned char *)pci_ioaddr(port);
        else
                v = (*port2adr(port)) & 0xff;
        ctrl_delay();
@@ -58,8 +54,6 @@ unsigned short sh7751se_inw(unsigned long port)
 {
         if (PXSEG(port))
                 return *(volatile unsigned short *)port;
-       else if (is_pci_ioaddr(port))
-                return *(volatile unsigned short *)pci_ioaddr(port);
        else if (port >= 0x2000)
                return *port2adr(port);
        else
@@ -71,8 +65,6 @@ unsigned int sh7751se_inl(unsigned long port)
 {
         if (PXSEG(port))
                 return *(volatile unsigned long *)port;
-       else if (is_pci_ioaddr(port))
-                return *(volatile unsigned int *)pci_ioaddr(port);
        else if (port >= 0x2000)
                return *port2adr(port);
        else
@@ -85,8 +77,6 @@ void sh7751se_outb(unsigned char value, unsigned long port)
 
         if (PXSEG(port))
                 *(volatile unsigned char *)port = value;
-       else if (is_pci_ioaddr(port))
-               *((unsigned char*)pci_ioaddr(port)) = value;
        else
                *(port2adr(port)) = value;
 }
@@ -95,8 +85,6 @@ void sh7751se_outb_p(unsigned char value, unsigned long port)
 {
         if (PXSEG(port))
                 *(volatile unsigned char *)port = value;
-       else if (is_pci_ioaddr(port))
-               *((unsigned char*)pci_ioaddr(port)) = value;
        else
                *(port2adr(port)) = value;
        ctrl_delay();
@@ -106,8 +94,6 @@ void sh7751se_outw(unsigned short value, unsigned long port)
 {
         if (PXSEG(port))
                 *(volatile unsigned short *)port = value;
-       else if (is_pci_ioaddr(port))
-               *((unsigned short *)pci_ioaddr(port)) = value;
        else if (port >= 0x2000)
                *port2adr(port) = value;
        else
@@ -118,8 +104,6 @@ void sh7751se_outl(unsigned int value, unsigned long port)
 {
         if (PXSEG(port))
                 *(volatile unsigned long *)port = value;
-       else if (is_pci_ioaddr(port))
-               *((unsigned long*)pci_ioaddr(port)) = value;
        else
                maybebadio(port);
 }
diff --git a/arch/sh/boards/mach-se/7751/pci.c b/arch/sh/boards/mach-se/7751/pci.c
deleted file mode 100644 (file)
index 203b292..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * linux/arch/sh/boards/se/7751/pci.c
- *
- * Author:  Ian DaSilva (idasilva@mvista.com)
- *
- * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * PCI initialization for the Hitachi SH7751 Solution Engine board (MS7751SE01)
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-
-#include <asm/io.h>
-#include "../../../drivers/pci/pci-sh7751.h"
-
-#define PCIMCR_MRSET_OFF       0xBFFFFFFF
-#define PCIMCR_RFSH_OFF                0xFFFFFFFB
-
-/*
- * Only long word accesses of the PCIC's internal local registers and the
- * configuration registers from the CPU is supported.
- */
-#define PCIC_WRITE(x,v) writel((v), PCI_REG(x))
-#define PCIC_READ(x) readl(PCI_REG(x))
-
-/*
- * Description:  This function sets up and initializes the pcic, sets
- * up the BARS, maps the DRAM into the address space etc, etc.
- */
-int __init pcibios_init_platform(void)
-{
-   unsigned long bcr1, wcr1, wcr2, wcr3, mcr;
-   unsigned short bcr2;
-
-   /*
-    * Initialize the slave bus controller on the pcic.  The values used
-    * here should not be hardcoded, but they should be taken from the bsc
-    * on the processor, to make this function as generic as possible.
-    * (i.e. Another sbc may usr different SDRAM timing settings -- in order
-    * for the pcic to work, its settings need to be exactly the same.)
-    */
-   bcr1 = (*(volatile unsigned long*)(SH7751_BCR1));
-   bcr2 = (*(volatile unsigned short*)(SH7751_BCR2));
-   wcr1 = (*(volatile unsigned long*)(SH7751_WCR1));
-   wcr2 = (*(volatile unsigned long*)(SH7751_WCR2));
-   wcr3 = (*(volatile unsigned long*)(SH7751_WCR3));
-   mcr = (*(volatile unsigned long*)(SH7751_MCR));
-
-   bcr1 = bcr1 | 0x00080000;  /* Enable Bit 19, BREQEN */
-   (*(volatile unsigned long*)(SH7751_BCR1)) = bcr1;   
-
-   bcr1 = bcr1 | 0x40080000;  /* Enable Bit 19 BREQEN, set PCIC to slave */
-   PCIC_WRITE(SH7751_PCIBCR1, bcr1);    /* PCIC BCR1 */
-   PCIC_WRITE(SH7751_PCIBCR2, bcr2);     /* PCIC BCR2 */
-   PCIC_WRITE(SH7751_PCIWCR1, wcr1);     /* PCIC WCR1 */
-   PCIC_WRITE(SH7751_PCIWCR2, wcr2);     /* PCIC WCR2 */
-   PCIC_WRITE(SH7751_PCIWCR3, wcr3);     /* PCIC WCR3 */
-   mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
-   PCIC_WRITE(SH7751_PCIMCR, mcr);      /* PCIC MCR */
-
-
-   /* Enable all interrupts, so we know what to fix */
-   PCIC_WRITE(SH7751_PCIINTM, 0x0000c3ff);
-   PCIC_WRITE(SH7751_PCIAINTM, 0x0000380f);
-
-   /* Set up standard PCI config registers */
-   PCIC_WRITE(SH7751_PCICONF1,         0xF39000C7); /* Bus Master, Mem & I/O access */
-   PCIC_WRITE(SH7751_PCICONF2,         0x00000000); /* PCI Class code & Revision ID */
-   PCIC_WRITE(SH7751_PCICONF4,         0xab000001); /* PCI I/O address (local regs) */
-   PCIC_WRITE(SH7751_PCICONF5,         0x0c000000); /* PCI MEM address (local RAM)  */
-   PCIC_WRITE(SH7751_PCICONF6,         0xd0000000); /* PCI MEM address (unused)     */
-   PCIC_WRITE(SH7751_PCICONF11, 0x35051054); /* PCI Subsystem ID & Vendor ID */
-   PCIC_WRITE(SH7751_PCILSR0, 0x03f00000);   /* MEM (full 64M exposed)       */
-   PCIC_WRITE(SH7751_PCILSR1, 0x00000000);   /* MEM (unused)                 */
-   PCIC_WRITE(SH7751_PCILAR0, 0x0c000000);   /* MEM (direct map from PCI)    */
-   PCIC_WRITE(SH7751_PCILAR1, 0x00000000);   /* MEM (unused)                 */
-
-   /* Now turn it on... */
-   PCIC_WRITE(SH7751_PCICR, 0xa5000001);
-
-   /*
-    * Set PCIMBR and PCIIOBR here, assuming a single window
-    * (16M MEM, 256K IO) is enough.  If a larger space is
-    * needed, the readx/writex and inx/outx functions will
-    * have to do more (e.g. setting registers for each call).
-    */
-
-   /*
-    * Set the MBR so PCI address is one-to-one with window,
-    * meaning all calls go straight through... use BUG_ON to
-    * catch erroneous assumption.
-    */
-   BUG_ON(PCIBIOS_MIN_MEM != SH7751_PCI_MEMORY_BASE);
-
-   PCIC_WRITE(SH7751_PCIMBR, PCIBIOS_MIN_MEM);
-
-   /* Set IOBR for window containing area specified in pci.h */
-   PCIC_WRITE(SH7751_PCIIOBR, (PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK));
-
-   /* All done, may as well say so... */
-   printk("SH7751 PCI: Finished initialization of the PCI controller\n");
-
-   return 1;
-}
-
-int __init pcibios_map_platform_irq(u8 slot, u8 pin)
-{
-        switch (slot) {
-        case 0: return 13;
-        case 1: return 13;     /* AMD Ethernet controller */
-        case 2: return -1;
-        case 3: return -1;
-        case 4: return -1;
-        default:
-                printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
-                return -1;
-        }
-}
-
-static struct resource sh7751_io_resource = {
-       .name   = "SH7751 IO",
-       .start  = SH7751_PCI_IO_BASE,
-       .end    = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
-       .flags  = IORESOURCE_IO
-};
-
-static struct resource sh7751_mem_resource = {
-       .name   = "SH7751 mem",
-       .start  = SH7751_PCI_MEMORY_BASE,
-       .end    = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
-       .flags  = IORESOURCE_MEM
-};
-
-extern struct pci_ops sh7751_pci_ops;
-
-struct pci_channel board_pci_channels[] = {
-       { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
-       { NULL, NULL, NULL, 0, 0 },
-};
-
index 66ad292c9fc346b8f9a9bcb44114e44c1b028d9d..b8d43b638fcff2118cf007b8f9cc745e79a0917f 100644 (file)
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
-#include <asm/io.h>
+#include <linux/irq.h>
+#include <linux/io.h>
 #include <mach-se/mach/se7780.h>
 
+#define INTC_BASE      0xffd00000
+#define INTC_ICR1      (INTC_BASE+0x1c)
+
 /*
  * Initialize IRQ setting
  */
@@ -43,4 +46,24 @@ void __init init_se7780_IRQ(void)
        ctrl_outw((IRQPIN_PCCPW << IRQPOS_PCCPW), FPGA_INTSEL3);
 
        plat_irq_setup_pins(IRQ_MODE_IRQ); /* install handlers for IRQ0-7 */
+
+       /* ICR1: detect low level(for 2ndcut) */
+       ctrl_outl(0xAAAA0000, INTC_ICR1);
+
+       /*
+        * FPGA PCISEL register initialize
+        *
+        *  CPU  || SLOT1 | SLOT2 | S-ATA | USB
+        *  -------------------------------------
+        *  INTA || INTA  | INTD  |  --   | INTB
+        *  -------------------------------------
+        *  INTB || INTB  | INTA  |  --   | INTC
+        *  -------------------------------------
+        *  INTC || INTC  | INTB  | INTA  |  --
+        *  -------------------------------------
+        *  INTD || INTD  | INTC  |  --   | INTA
+        *  -------------------------------------
+        */
+       ctrl_outw(0x0013, FPGA_PCI_INTSEL1);
+       ctrl_outw(0xE402, FPGA_PCI_INTSEL2);
 }
index 2de42bae4b4f8da56cf4bde589c4c3b2e7c08286..b537e238c6bcddcf211eafbd74e17e787c5eb81f 100644 (file)
@@ -7,3 +7,4 @@ obj-$(CONFIG_SH_7751_SOLUTION_ENGINE)   += 7751/
 obj-$(CONFIG_SH_7780_SOLUTION_ENGINE)  += 7780/
 obj-$(CONFIG_SH_7343_SOLUTION_ENGINE)  += 7343/
 obj-$(CONFIG_SH_7721_SOLUTION_ENGINE)  += 7721/
+obj-$(CONFIG_SH_7724_SOLUTION_ENGINE)  += 7724/
index 0a9266bb51c58bcd7309dcf15b5870b563a08f11..a8b9f844ab5b5ed1ea8fe1e275c6f3da6a0cb676 100644 (file)
 #define RTC_BUSY       1
 #define RTC_STOP       2
 
-extern spinlock_t rtc_lock;
+static DEFINE_SPINLOCK(sh03_rtc_lock);
 
 unsigned long get_cmos_time(void)
 {
        unsigned int year, mon, day, hour, min, sec;
 
-       spin_lock(&rtc_lock);
+       spin_lock(&sh03_rtc_lock);
  again:
        do {
                sec  = (ctrl_inb(RTC_SEC1) & 0xf) + (ctrl_inb(RTC_SEC10) & 0x7) * 10;
@@ -73,7 +73,7 @@ unsigned long get_cmos_time(void)
                goto again;
        }
 
-       spin_unlock(&rtc_lock);
+       spin_unlock(&sh03_rtc_lock);
        return mktime(year, mon, day, hour, min, sec);
 }
 
@@ -91,7 +91,7 @@ static int set_rtc_mmss(unsigned long nowtime)
        int i;
 
        /* gets recalled with irq locally disabled */
-       spin_lock(&rtc_lock);
+       spin_lock(&sh03_rtc_lock);
        for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
                if (!(ctrl_inb(RTC_CTL) & RTC_BUSY))
                        break;
@@ -113,7 +113,7 @@ static int set_rtc_mmss(unsigned long nowtime)
                       cmos_minutes, real_minutes);
                retval = -1;
        }
-       spin_unlock(&rtc_lock);
+       spin_unlock(&sh03_rtc_lock);
 
        return retval;
 }
index 0f4824264557deae48a2b6719a475ea3f0b21175..476650e42dbc05ff8e466866e87a5b56555b2ec5 100644 (file)
@@ -36,8 +36,6 @@ unsigned char snapgear_inb(unsigned long port)
 {
        if (PXSEG(port))
                return *(volatile unsigned char *)port;
-       else if (is_pci_ioaddr(port))
-               return *(volatile unsigned char *)pci_ioaddr(port);
        else
                return (*port2adr(port)) & 0xff;
 }
@@ -48,8 +46,6 @@ unsigned char snapgear_inb_p(unsigned long port)
 
        if (PXSEG(port))
                v = *(volatile unsigned char *)port;
-       else if (is_pci_ioaddr(port))
-               v = *(volatile unsigned char *)pci_ioaddr(port);
        else
                v = (*port2adr(port))&0xff;
        ctrl_delay();
@@ -60,8 +56,6 @@ unsigned short snapgear_inw(unsigned long port)
 {
        if (PXSEG(port))
                return *(volatile unsigned short *)port;
-       else if (is_pci_ioaddr(port))
-               return *(volatile unsigned short *)pci_ioaddr(port);
        else if (port >= 0x2000)
                return *port2adr(port);
        else
@@ -73,8 +67,6 @@ unsigned int snapgear_inl(unsigned long port)
 {
        if (PXSEG(port))
                return *(volatile unsigned long *)port;
-       else if (is_pci_ioaddr(port))
-               return *(volatile unsigned int *)pci_ioaddr(port);
        else if (port >= 0x2000)
                return *port2adr(port);
        else
@@ -87,8 +79,6 @@ void snapgear_outb(unsigned char value, unsigned long port)
 
        if (PXSEG(port))
                *(volatile unsigned char *)port = value;
-       else if (is_pci_ioaddr(port))
-               *((unsigned char*)pci_ioaddr(port)) = value;
        else
                *(port2adr(port)) = value;
 }
@@ -97,8 +87,6 @@ void snapgear_outb_p(unsigned char value, unsigned long port)
 {
        if (PXSEG(port))
                *(volatile unsigned char *)port = value;
-       else if (is_pci_ioaddr(port))
-               *((unsigned char*)pci_ioaddr(port)) = value;
        else
                *(port2adr(port)) = value;
        ctrl_delay();
@@ -108,8 +96,6 @@ void snapgear_outw(unsigned short value, unsigned long port)
 {
        if (PXSEG(port))
                *(volatile unsigned short *)port = value;
-       else if (is_pci_ioaddr(port))
-               *((unsigned short *)pci_ioaddr(port)) = value;
        else if (port >= 0x2000)
                *port2adr(port) = value;
        else
@@ -120,8 +106,6 @@ void snapgear_outl(unsigned int value, unsigned long port)
 {
        if (PXSEG(port))
                *(volatile unsigned long *)port = value;
-       else if (is_pci_ioaddr(port))
-               *((unsigned long*)pci_ioaddr(port)) = value;
        else
                maybebadio(port);
 }
index dec3db0ee933ba61a11d0438f64c81201d3edd0b..15577ff1f7153b68a0b3432183266a194625c381 100644 (file)
@@ -35,8 +35,6 @@ unsigned char sh7751systemh_inb(unsigned long port)
 {
        if (PXSEG(port))
                return *(volatile unsigned char *)port;
-       else if (is_pci_ioaddr(port))
-               return *(volatile unsigned char *)pci_ioaddr(port);
        else if (port <= 0x3F1)
                return *(volatile unsigned char *)ETHER_IOMAP(port);
        else
@@ -49,8 +47,6 @@ unsigned char sh7751systemh_inb_p(unsigned long port)
 
         if (PXSEG(port))
                 v = *(volatile unsigned char *)port;
-       else if (is_pci_ioaddr(port))
-                v = *(volatile unsigned char *)pci_ioaddr(port);
        else if (port <= 0x3F1)
                v = *(volatile unsigned char *)ETHER_IOMAP(port);
        else
@@ -63,8 +59,6 @@ unsigned short sh7751systemh_inw(unsigned long port)
 {
         if (PXSEG(port))
                 return *(volatile unsigned short *)port;
-       else if (is_pci_ioaddr(port))
-                return *(volatile unsigned short *)pci_ioaddr(port);
        else if (port >= 0x2000)
                return *port2adr(port);
        else if (port <= 0x3F1)
@@ -78,8 +72,6 @@ unsigned int sh7751systemh_inl(unsigned long port)
 {
         if (PXSEG(port))
                 return *(volatile unsigned long *)port;
-       else if (is_pci_ioaddr(port))
-                return *(volatile unsigned int *)pci_ioaddr(port);
        else if (port >= 0x2000)
                return *port2adr(port);
        else if (port <= 0x3F1)
@@ -94,8 +86,6 @@ void sh7751systemh_outb(unsigned char value, unsigned long port)
 
         if (PXSEG(port))
                 *(volatile unsigned char *)port = value;
-       else if (is_pci_ioaddr(port))
-               *((unsigned char*)pci_ioaddr(port)) = value;
        else if (port <= 0x3F1)
                *(volatile unsigned char *)ETHER_IOMAP(port) = value;
        else
@@ -106,8 +96,6 @@ void sh7751systemh_outb_p(unsigned char value, unsigned long port)
 {
         if (PXSEG(port))
                 *(volatile unsigned char *)port = value;
-       else if (is_pci_ioaddr(port))
-               *((unsigned char*)pci_ioaddr(port)) = value;
        else if (port <= 0x3F1)
                *(volatile unsigned char *)ETHER_IOMAP(port) = value;
        else
@@ -119,8 +107,6 @@ void sh7751systemh_outw(unsigned short value, unsigned long port)
 {
         if (PXSEG(port))
                 *(volatile unsigned short *)port = value;
-       else if (is_pci_ioaddr(port))
-               *((unsigned short *)pci_ioaddr(port)) = value;
        else if (port >= 0x2000)
                *port2adr(port) = value;
        else if (port <= 0x3F1)
@@ -133,8 +119,6 @@ void sh7751systemh_outl(unsigned int value, unsigned long port)
 {
         if (PXSEG(port))
                 *(volatile unsigned long *)port = value;
-       else if (is_pci_ioaddr(port))
-               *((unsigned long*)pci_ioaddr(port)) = value;
        else
                maybebadio(port);
 }
index 4badad4c6f30329036768e76c0bfa148c1ec0034..0130e9826aca619f086378b92cc59eb205ea7aa1 100644 (file)
@@ -17,8 +17,6 @@ u8 titan_inb(unsigned long port)
 {
         if (PXSEG(port))
                 return ctrl_inb(port);
-        else if (is_pci_ioaddr(port))
-                return ctrl_inb(pci_ioaddr(port));
         return ctrl_inw(port2adr(port)) & 0xff;
 }
 
@@ -28,8 +26,6 @@ u8 titan_inb_p(unsigned long port)
 
         if (PXSEG(port))
                 v = ctrl_inb(port);
-        else if (is_pci_ioaddr(port))
-                v = ctrl_inb(pci_ioaddr(port));
         else
                 v = ctrl_inw(port2adr(port)) & 0xff;
         ctrl_delay();
@@ -40,8 +36,6 @@ u16 titan_inw(unsigned long port)
 {
         if (PXSEG(port))
                 return ctrl_inw(port);
-        else if (is_pci_ioaddr(port))
-                return ctrl_inw(pci_ioaddr(port));
         else if (port >= 0x2000)
                 return ctrl_inw(port2adr(port));
         else
@@ -53,8 +47,6 @@ u32 titan_inl(unsigned long port)
 {
         if (PXSEG(port))
                 return ctrl_inl(port);
-        else if (is_pci_ioaddr(port))
-                return ctrl_inl(pci_ioaddr(port));
         else if (port >= 0x2000)
                 return ctrl_inw(port2adr(port));
         else
@@ -66,8 +58,6 @@ void titan_outb(u8 value, unsigned long port)
 {
         if (PXSEG(port))
                 ctrl_outb(value, port);
-        else if (is_pci_ioaddr(port))
-                ctrl_outb(value, pci_ioaddr(port));
         else
                 ctrl_outw(value, port2adr(port));
 }
@@ -76,8 +66,6 @@ void titan_outb_p(u8 value, unsigned long port)
 {
         if (PXSEG(port))
                 ctrl_outb(value, port);
-        else if (is_pci_ioaddr(port))
-                ctrl_outb(value, pci_ioaddr(port));
         else
                 ctrl_outw(value, port2adr(port));
         ctrl_delay();
@@ -87,8 +75,6 @@ void titan_outw(u16 value, unsigned long port)
 {
         if (PXSEG(port))
                 ctrl_outw(value, port);
-        else if (is_pci_ioaddr(port))
-                ctrl_outw(value, pci_ioaddr(port));
         else if (port >= 0x2000)
                 ctrl_outw(value, port2adr(port));
         else
@@ -99,8 +85,6 @@ void titan_outl(u32 value, unsigned long port)
 {
         if (PXSEG(port))
                 ctrl_outl(value, port);
-        else if (is_pci_ioaddr(port))
-                ctrl_outl(value, pci_ioaddr(port));
         else
                 maybebadio(port);
 }
@@ -117,10 +101,8 @@ void titan_outsl(unsigned long port, const void *src, unsigned long count)
 
 void __iomem *titan_ioport_map(unsigned long port, unsigned int size)
 {
-       if (PXSEG(port) || is_pci_memaddr(port))
+       if (PXSEG(port))
                return (void __iomem *)port;
-       else if (is_pci_ioaddr(port))
-               return (void __iomem *)pci_ioaddr(port);
 
        return (void __iomem *)port2adr(port);
 }
index 95483d16125882d69d24620f9f8d5a8c7e736c98..78efb04c28f3dfb2362e6610318491a99e08ce54 100644 (file)
@@ -20,9 +20,6 @@ CONFIG_BOOT_LINK_OFFSET       ?= 0x00800000
 CONFIG_ZERO_PAGE_OFFSET        ?= 0x00001000
 CONFIG_ENTRY_OFFSET    ?= 0x00001000
 
-export CONFIG_PAGE_OFFSET CONFIG_MEMORY_START CONFIG_BOOT_LINK_OFFSET \
-       CONFIG_ZERO_PAGE_OFFSET CONFIG_ENTRY_OFFSET
-
 targets := zImage vmlinux.srec uImage uImage.srec
 subdir- := compressed
 
@@ -43,6 +40,9 @@ KERNEL_MEMORY := $(shell /bin/bash -c 'printf "0x%08x" \
                     $$[$(CONFIG_MEMORY_START)]')
 endif
 
+export CONFIG_PAGE_OFFSET CONFIG_MEMORY_START CONFIG_BOOT_LINK_OFFSET \
+       CONFIG_ZERO_PAGE_OFFSET CONFIG_ENTRY_OFFSET KERNEL_MEMORY
+
 KERNEL_LOAD    := $(shell /bin/bash -c 'printf "0x%08x" \
                     $$[$(CONFIG_PAGE_OFFSET)  + \
                        $(KERNEL_MEMORY) + \
index efb01dc3c8c3aaa35ece6e2e21a428e1d1c0aa40..9531bf1b7c2f878b632f154f5e9a4bd06717758b 100644 (file)
@@ -1,5 +1,47 @@
-ifeq ($(CONFIG_SUPERH32),y)
-include ${srctree}/arch/sh/boot/compressed/Makefile_32
-else
-include ${srctree}/arch/sh/boot/compressed/Makefile_64
+#
+# linux/arch/sh/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+
+targets                := vmlinux vmlinux.bin vmlinux.bin.gz \
+                  head_$(BITS).o misc_$(BITS).o piggy.o
+
+OBJECTS = $(obj)/head_$(BITS).o $(obj)/misc_$(BITS).o $(obj)/cache.o
+
+ifdef CONFIG_SH_STANDARD_BIOS
+OBJECTS += $(obj)/../../kernel/sh_bios.o
 endif
+
+#
+# IMAGE_OFFSET is the load offset of the compression loader
+#
+IMAGE_OFFSET   := $(shell /bin/bash -c 'printf "0x%08x" \
+                    $$[$(CONFIG_PAGE_OFFSET)  + \
+                       $(KERNEL_MEMORY) + \
+                       $(CONFIG_BOOT_LINK_OFFSET)]')
+
+LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
+
+ifeq ($(CONFIG_FUNCTION_TRACER),y)
+ORIG_CFLAGS := $(KBUILD_CFLAGS)
+KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
+endif
+
+LDFLAGS_vmlinux := --oformat $(ld-bfd) -Ttext $(IMAGE_OFFSET) -e startup \
+                  -T $(obj)/../../kernel/vmlinux.lds
+
+$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE
+       $(call if_changed,ld)
+       @:
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+       $(call if_changed,objcopy)
+
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,gzip)
+
+OBJCOPYFLAGS += -R .empty_zero_page
+
+$(obj)/piggy.o: $(obj)/piggy.S $(obj)/vmlinux.bin.gz FORCE
+       $(call if_changed,as_o_S)
diff --git a/arch/sh/boot/compressed/Makefile_32 b/arch/sh/boot/compressed/Makefile_32
deleted file mode 100644 (file)
index b96a055..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#
-# linux/arch/sh/boot/compressed/Makefile
-#
-# create a compressed vmlinux image from the original vmlinux
-#
-
-targets                := vmlinux vmlinux.bin vmlinux.bin.gz \
-                  head_32.o misc_32.o piggy.o
-
-OBJECTS = $(obj)/head_32.o $(obj)/misc_32.o
-
-ifdef CONFIG_SH_STANDARD_BIOS
-OBJECTS += $(obj)/../../kernel/sh_bios.o
-endif
-
-#
-# IMAGE_OFFSET is the load offset of the compression loader
-#
-IMAGE_OFFSET   := $(shell /bin/bash -c 'printf "0x%08x" \
-                    $$[$(CONFIG_PAGE_OFFSET)  + \
-                       $(CONFIG_MEMORY_START) + \
-                       $(CONFIG_BOOT_LINK_OFFSET)]')
-
-LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
-
-ifeq ($(CONFIG_FUNCTION_TRACER),y)
-ORIG_CFLAGS := $(KBUILD_CFLAGS)
-KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
-endif
-
-LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup -T $(obj)/../../kernel/vmlinux.lds
-
-$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE
-       $(call if_changed,ld)
-       @:
-
-$(obj)/vmlinux.bin: vmlinux FORCE
-       $(call if_changed,objcopy)
-
-$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
-       $(call if_changed,gzip)
-
-OBJCOPYFLAGS += -R .empty_zero_page
-
-$(obj)/piggy.o: $(obj)/piggy.S $(obj)/vmlinux.bin.gz FORCE
-       $(call if_changed,as_o_S)
diff --git a/arch/sh/boot/compressed/Makefile_64 b/arch/sh/boot/compressed/Makefile_64
deleted file mode 100644 (file)
index 658d4f9..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# arch/sh/boot/compressed/Makefile_64
-#
-# create a compressed vmlinux image from the original vmlinux
-#
-# Copyright (C) 2002 Stuart Menefy
-# Copyright (C) 2004 Paul Mundt
-#
-# 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.
-#
-
-targets                := vmlinux vmlinux.bin vmlinux.bin.gz \
-                  head_64.o misc_64.o cache.o piggy.o
-
-OBJECTS                := $(obj)/vmlinux_64.lds $(obj)/head_64.o $(obj)/misc_64.o \
-                  $(obj)/cache.o
-
-#
-# ZIMAGE_OFFSET is the load offset of the compression loader
-# (4M for the kernel plus 64K for this loader)
-#
-ZIMAGE_OFFSET  := $(shell /bin/bash -c 'printf "0x%08x" \
-                    $$[$(CONFIG_PAGE_OFFSET)+0x400000+0x10000]')
-
-LDFLAGS_vmlinux := -Ttext $(ZIMAGE_OFFSET) -e startup \
-                   -T $(obj)/../../kernel/vmlinux.lds
-
-$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE
-       $(call if_changed,ld)
-       @:
-
-$(obj)/vmlinux.bin: vmlinux FORCE
-       $(call if_changed,objcopy)
-
-$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
-       $(call if_changed,gzip)
-
-OBJCOPYFLAGS += -R .empty_zero_page
-
-$(obj)/piggy.o: $(obj)/piggy.S $(obj)/vmlinux.bin.gz FORCE
-       $(call if_changed,as_o_S)
index 622eac3cf556c10f9496fb11c4d85f6609218e3b..9993113c671386c359561ea3393deb3c0cfe909f 100644 (file)
@@ -14,6 +14,7 @@
  *   Copyright (C) 2002 Stuart Menefy (stuart.menefy@st.com)
  */
 #include <asm/cache.h>
+#include <asm/tlb.h>
 #include <cpu/mmu_context.h>
 #include <cpu/registers.h>
 
 #define        ICCR0_INIT_VAL  ICCR0_ON | ICCR0_ICI            /* ICE + ICI */
 #define        ICCR1_INIT_VAL  ICCR1_NOLOCK                    /* No locking */
 
-#if 1
 #define        OCCR0_INIT_VAL  OCCR0_ON | OCCR0_OCI | OCCR0_WB /* OCE + OCI + WB */
-#else
-#define        OCCR0_INIT_VAL  OCCR0_OFF
-#endif
 #define        OCCR1_INIT_VAL  OCCR1_NOLOCK                    /* No locking */
 
        .text
diff --git a/arch/sh/boot/compressed/vmlinux_64.lds b/arch/sh/boot/compressed/vmlinux_64.lds
deleted file mode 100644 (file)
index 59c2ef4..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * ld script to make compressed SuperH/shmedia Linux kernel+decompression
- *             bootstrap
- * Modified by Stuart Menefy from arch/sh/vmlinux.lds.S written by Niibe Yutaka
- */
-
-
-#ifdef CONFIG_LITTLE_ENDIAN
-/* OUTPUT_FORMAT("elf32-sh64l-linux", "elf32-sh64l-linux", "elf32-sh64l-linux") */
-#define NOP 0x6ff0fff0
-#else
-/* OUTPUT_FORMAT("elf32-sh64", "elf32-sh64", "elf32-sh64") */
-#define NOP 0xf0fff06f
-#endif
-
-OUTPUT_FORMAT("elf32-sh64-linux")
-OUTPUT_ARCH(sh)
-ENTRY(_start)
-
-#define ALIGNED_GAP(section, align) (((ADDR(section)+SIZEOF(section)+(align)-1) & ~((align)-1))-ADDR(section))
-#define FOLLOWING(section, align) AT (LOADADDR(section) + ALIGNED_GAP(section,align))
-
-SECTIONS
-{
-  _text = .;                   /* Text and read-only data */
-
-  .text : {
-       *(.text)
-       *(.text64)
-       *(.text..SHmedia32)
-       *(.fixup)
-       *(.gnu.warning)
-       } = NOP
-  . = ALIGN(4);
-  .rodata : { *(.rodata) }
-
-  /* There is no 'real' reason for eight byte alignment, four would work
-   * as well, but gdb downloads much (*4) faster with this.
-   */
-  . = ALIGN(8);
-  .image : { *(.image) }
-  . = ALIGN(4);
-  _etext = .;                  /* End of text section */
-
-  .data :                      /* Data */
-       FOLLOWING(.image, 4)
-       {
-       _data = .;
-       *(.data)
-       }
-  _data_image = LOADADDR(.data);/* Address of data section in ROM */
-
-  _edata = .;                  /* End of data section */
-
-  .stack : { stack = .;  _stack = .; }
-
-  . = ALIGN(4);
-  __bss_start = .;             /* BSS */
-  .bss : {
-       *(.bss)
-       }
-  . = ALIGN(4);
-  _end = . ;
-}
index f43d18373f224b0c1327d2ca94ed55261e9dcdf5..a5ab2eccdaa65117656d852fd461e39f1aff05cc 100644 (file)
@@ -34,11 +34,6 @@ config HD64461_IRQ
 
          Do not change this unless you know what you are doing.
 
-config HD64461_IOBASE
-       hex "HD64461 start address"
-       depends on HD64461
-       default "0xb0000000"
-
 config HD64461_ENABLER
        bool "HD64461 PCMCIA enabler"
        depends on HD64461
index 25ef910615217a5c7115d19e77d9008c68085b67..50aa0c1f76ea76964b6762efa546e0260efeebe7 100644 (file)
@@ -80,7 +80,7 @@ int __init setup_hd64461(void)
 
        printk(KERN_INFO
               "HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n",
-              CONFIG_HD64461_IOBASE, CONFIG_HD64461_IRQ, HD64461_IRQBASE,
+              HD64461_IOBASE, CONFIG_HD64461_IRQ, HD64461_IRQBASE,
               HD64461_IRQBASE + 15);
 
 /* Should be at processor specific part.. */
index c8d982a8a2e64500aafe17dd868c0c1b31a44fe3..022f70e0ea03e745b688b82b338ff813879b2819 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 17:46:53 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:42:06 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -74,6 +75,7 @@ CONFIG_EMBEDDED=y
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
 # CONFIG_KALLSYMS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -92,12 +94,15 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -110,7 +115,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -159,6 +163,7 @@ CONFIG_ARCH_SHMOBILE=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 CONFIG_CPU_SUBTYPE_SH7723=y
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -168,8 +173,6 @@ CONFIG_CPU_SUBTYPE_SH7723=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -573,6 +576,7 @@ CONFIG_SCSI_WAIT_SCAN=m
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
 # CONFIG_SCSI_OSD_INITIATOR is not set
@@ -695,6 +699,7 @@ CONFIG_DEVKMEM=y
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_SH_SCI=y
 CONFIG_SERIAL_SH_SCI_NR_UARTS=6
 CONFIG_SERIAL_SH_SCI_CONSOLE=y
@@ -1030,6 +1035,7 @@ CONFIG_EXT2_FS_POSIX_ACL=y
 CONFIG_EXT2_FS_SECURITY=y
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
 CONFIG_EXT3_FS_SECURITY=y
@@ -1051,6 +1057,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1100,6 +1111,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -1191,10 +1203,24 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -1303,6 +1329,7 @@ CONFIG_CRYPTO_CBC=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index fa5fc1e1e980bebfe62a3c35cf5bc795e5ee4263..40301f86a45c1cddbbc6ec9d09d45bcceb6fa2f1 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 17:49:14 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:42:53 2009
 #
 CONFIG_SUPERH=y
 # CONFIG_SUPERH32 is not set
@@ -40,6 +40,7 @@ CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 # CONFIG_SYSVIPC is not set
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
@@ -70,6 +71,7 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -89,10 +91,13 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -105,7 +110,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -127,39 +131,6 @@ CONFIG_DEFAULT_IOSCHED="cfq"
 # System type
 #
 CONFIG_CPU_SH5=y
-# CONFIG_CPU_SUBTYPE_SH7619 is not set
-# CONFIG_CPU_SUBTYPE_SH7201 is not set
-# CONFIG_CPU_SUBTYPE_SH7203 is not set
-# CONFIG_CPU_SUBTYPE_SH7206 is not set
-# CONFIG_CPU_SUBTYPE_SH7263 is not set
-# CONFIG_CPU_SUBTYPE_MXG is not set
-# CONFIG_CPU_SUBTYPE_SH7705 is not set
-# CONFIG_CPU_SUBTYPE_SH7706 is not set
-# CONFIG_CPU_SUBTYPE_SH7707 is not set
-# CONFIG_CPU_SUBTYPE_SH7708 is not set
-# CONFIG_CPU_SUBTYPE_SH7709 is not set
-# CONFIG_CPU_SUBTYPE_SH7710 is not set
-# CONFIG_CPU_SUBTYPE_SH7712 is not set
-# CONFIG_CPU_SUBTYPE_SH7720 is not set
-# CONFIG_CPU_SUBTYPE_SH7721 is not set
-# CONFIG_CPU_SUBTYPE_SH7750 is not set
-# CONFIG_CPU_SUBTYPE_SH7091 is not set
-# CONFIG_CPU_SUBTYPE_SH7750R is not set
-# CONFIG_CPU_SUBTYPE_SH7750S is not set
-# CONFIG_CPU_SUBTYPE_SH7751 is not set
-# CONFIG_CPU_SUBTYPE_SH7751R is not set
-# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
-# CONFIG_CPU_SUBTYPE_SH7723 is not set
-# CONFIG_CPU_SUBTYPE_SH7763 is not set
-# CONFIG_CPU_SUBTYPE_SH7770 is not set
-# CONFIG_CPU_SUBTYPE_SH7780 is not set
-# CONFIG_CPU_SUBTYPE_SH7785 is not set
-# CONFIG_CPU_SUBTYPE_SH7786 is not set
-# CONFIG_CPU_SUBTYPE_SHX3 is not set
-# CONFIG_CPU_SUBTYPE_SH7343 is not set
-# CONFIG_CPU_SUBTYPE_SH7722 is not set
-# CONFIG_CPU_SUBTYPE_SH7366 is not set
 CONFIG_CPU_SUBTYPE_SH5_101=y
 # CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
@@ -279,8 +250,6 @@ CONFIG_BOOT_LINK_OFFSET=0x00800000
 #
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCI_LEGACY=y
@@ -492,6 +461,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_MPT2SAS is not set
 # CONFIG_SCSI_HPTIOP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_FCOE is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
@@ -568,6 +538,7 @@ CONFIG_NETDEV_1000=y
 # CONFIG_E1000E is not set
 # CONFIG_IP1000 is not set
 # CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -591,6 +562,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
 # CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
+# CONFIG_VXGE is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_NIU is not set
@@ -779,6 +751,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_F71805F is not set
 # CONFIG_SENSORS_F71882FG is not set
 # CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
@@ -1042,7 +1015,6 @@ CONFIG_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1082,6 +1054,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -1104,6 +1077,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1146,8 +1124,13 @@ CONFIG_MINIX_FS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -1208,6 +1191,9 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 CONFIG_SCHEDSTATS=y
 # CONFIG_TIMER_STATS is not set
@@ -1241,15 +1227,21 @@ CONFIG_FRAME_POINTER=y
 # CONFIG_LATENCYTOP is not set
 # CONFIG_SYSCTL_SYSCALL_CHECK is not set
 # CONFIG_PAGE_POISONING is not set
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 # CONFIG_EARLY_SCIF_CONSOLE is not set
 # CONFIG_DEBUG_BOOTMEM is not set
@@ -1354,6 +1346,7 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 5c1123640142bc2bc024ed5ecf038219c308e35d..1f3cc98330bfd5f3c277e967938c99a01e9c6545 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 17:51:48 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:44:27 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -71,6 +72,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -90,6 +92,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 CONFIG_PROFILING=y
+# CONFIG_MARKERS is not set
 # CONFIG_OPROFILE is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
@@ -98,6 +101,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -110,7 +115,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -156,6 +160,7 @@ CONFIG_CPU_SUBTYPE_SH7091=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -165,8 +170,6 @@ CONFIG_CPU_SUBTYPE_SH7091=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -271,7 +274,7 @@ CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_SH_DMA_API=y
 CONFIG_SH_DMA=y
 CONFIG_SH_DMA_IRQ_MULTI=y
-CONFIG_NR_ONCHIP_DMA_CHANNELS=6
+CONFIG_NR_ONCHIP_DMA_CHANNELS=4
 CONFIG_NR_DMA_CHANNELS_BOOL=y
 CONFIG_NR_DMA_CHANNELS=9
 # CONFIG_PVR2_DMA is not set
@@ -320,7 +323,6 @@ CONFIG_CMDLINE="console=ttySC1,115200 panic=3"
 CONFIG_MAPLE=y
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCI_LEGACY=y
@@ -602,6 +604,7 @@ CONFIG_INPUT_MOUSE=y
 # CONFIG_MOUSE_APPLETOUCH is not set
 # CONFIG_MOUSE_BCM5974 is not set
 # CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_MAPLE is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
@@ -812,7 +815,6 @@ CONFIG_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
@@ -866,6 +868,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -910,6 +917,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
@@ -947,10 +955,24 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -1051,6 +1073,7 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index f4c34b039312f8b8617b5c1c473a78bf6d44d024..d7092457ddc70bb51350afc9dcd02182e924c02b 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 17:54:02 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:45:04 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -56,6 +57,7 @@ CONFIG_EMBEDDED=y
 # CONFIG_UID16 is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_PRINTK is not set
 # CONFIG_BUG is not set
@@ -74,12 +76,15 @@ CONFIG_SHMEM=y
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_BASE_SMALL=1
 # CONFIG_MODULES is not set
@@ -114,6 +119,7 @@ CONFIG_CPU_SUBTYPE_SH7705=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -123,8 +129,6 @@ CONFIG_CPU_SUBTYPE_SH7705=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -381,6 +385,10 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+
 #
 # Pseudo filesystems
 #
@@ -409,10 +417,22 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -426,6 +446,7 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 # CONFIG_CRYPTO is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 7825c2699f18f731bd10aa1bcac618393c2011de..a822b1d8c11609ea652c33c17bd3eef98325248b 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 17:54:57 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:45:25 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -40,6 +41,7 @@ CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 # CONFIG_TASKSTATS is not set
@@ -67,7 +69,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -77,6 +78,7 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -96,6 +98,7 @@ CONFIG_COMPAT_BRK=y
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_IOREMAP_PROT=y
@@ -103,6 +106,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -115,7 +120,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -161,6 +165,7 @@ CONFIG_CPU_SH4=y
 CONFIG_CPU_SUBTYPE_SH7760=y
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -170,8 +175,6 @@ CONFIG_CPU_SUBTYPE_SH7760=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -815,6 +818,7 @@ CONFIG_EXT2_FS_XATTR=y
 # CONFIG_EXT2_FS_SECURITY is not set
 CONFIG_EXT2_FS_XIP=y
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -838,6 +842,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_FUSE_FS is not set
 CONFIG_GENERIC_ACL=y
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -883,6 +892,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
@@ -964,6 +974,9 @@ CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
 CONFIG_TIMER_STATS=y
@@ -1001,6 +1014,7 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -1010,9 +1024,14 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 # CONFIG_PREEMPT_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1126,6 +1145,7 @@ CONFIG_CRYPTO_DES=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index ebb4c37abaa6ee0705a385984a4654fdc8409561..c5b50077913dd0f632a8fce329f4f3ff5716e343 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 17:58:18 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:46:26 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -78,6 +79,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -106,6 +108,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -117,7 +121,6 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -164,6 +167,7 @@ CONFIG_CPU_SH4A=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 CONFIG_CPU_SUBTYPE_SH7763=y
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -173,8 +177,6 @@ CONFIG_CPU_SUBTYPE_SH7763=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -548,6 +550,7 @@ CONFIG_SCSI_WAIT_SCAN=m
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
 # CONFIG_SCSI_OSD_INITIATOR is not set
@@ -919,6 +922,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -942,6 +946,11 @@ CONFIG_AUTOFS4_FS=y
 # CONFIG_FUSE_FS is not set
 CONFIG_GENERIC_ACL=y
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -985,8 +994,13 @@ CONFIG_CRAMFS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
@@ -1075,11 +1089,25 @@ CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
 CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -1179,6 +1207,7 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
index 82b113af08d32e30e451495e420d4038d0c84d75..8e13027eecc39d5bbe5996b9b27c82eb30552e17 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:01:05 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:47:15 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -67,6 +68,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -85,12 +87,15 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -98,7 +103,6 @@ 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
 
@@ -144,6 +148,7 @@ CONFIG_CPU_SUBTYPE_SH7709=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -153,8 +158,6 @@ CONFIG_CPU_SUBTYPE_SH7709=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -385,6 +388,7 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_SRP_ATTRS is not set
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
 # CONFIG_SCSI_DH is not set
@@ -431,6 +435,7 @@ CONFIG_KEYBOARD_HP6XX=y
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_AD7879 is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
@@ -673,6 +678,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -719,6 +729,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 
 #
 # Partition Types
@@ -786,10 +797,23 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -898,6 +922,7 @@ CONFIG_CRYPTO_MD5=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index b6fa4a7599d0116e076cc9a448ac775f59e55a44..7f549aef0dfd19909780e906ae0ef84a70a173fb 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:02:54 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:47:48 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -69,6 +70,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -88,6 +90,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_IOREMAP_PROT=y
@@ -95,6 +98,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -107,7 +112,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -153,6 +157,7 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -162,8 +167,6 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -292,8 +295,6 @@ CONFIG_BOOT_LINK_OFFSET=0x00800000
 #
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCI_LEGACY=y
@@ -602,6 +603,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_MPT2SAS is not set
 # CONFIG_SCSI_HPTIOP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_FCOE is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
@@ -706,6 +708,7 @@ CONFIG_NETDEV_1000=y
 # CONFIG_E1000E is not set
 # CONFIG_IP1000 is not set
 # CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -729,6 +732,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
 # CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
+# CONFIG_VXGE is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_NIU is not set
@@ -922,6 +926,7 @@ CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
 # CONFIG_SOC_CAMERA is not set
 CONFIG_V4L_USB_DRIVERS=y
 # CONFIG_USB_VIDEO_CLASS is not set
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
 # CONFIG_USB_GSPCA is not set
 # CONFIG_VIDEO_HDPVR is not set
 CONFIG_VIDEO_USBVIDEO=m
@@ -994,15 +999,17 @@ CONFIG_USB_HID=m
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_HID_A4TECH=m
 CONFIG_HID_APPLE=m
 CONFIG_HID_BELKIN=m
 CONFIG_HID_CHERRY=m
 CONFIG_HID_CHICONY=m
 CONFIG_HID_CYPRESS=m
+# CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=m
+# CONFIG_HID_KYE is not set
 CONFIG_HID_GYRATION=m
+# CONFIG_HID_KENSINGTON is not set
 CONFIG_HID_LOGITECH=m
 # CONFIG_LOGITECH_FF is not set
 # CONFIG_LOGIRUMBLEPAD2_FF is not set
@@ -1197,6 +1204,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -1221,6 +1229,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1270,10 +1283,15 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 CONFIG_UFS_FS=m
 # CONFIG_UFS_FS_WRITE is not set
 # CONFIG_UFS_DEBUG is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
@@ -1364,10 +1382,23 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 CONFIG_SH_STANDARD_BIOS=y
@@ -1469,6 +1500,7 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 92c515c4199f09ca75021b81c6f7cb549e4b03f1..a7db539f2800d7de021dc7640d825a1d69017c87 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:06:51 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:48:54 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -69,6 +70,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -88,6 +90,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_IOREMAP_PROT=y
@@ -95,6 +98,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -107,7 +112,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -153,6 +157,7 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -162,8 +167,6 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -293,8 +296,6 @@ CONFIG_CMDLINE="console=ttySC1,115200 root=/dev/sda1"
 #
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCI_LEGACY=y
@@ -542,6 +543,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_MPT2SAS is not set
 # CONFIG_SCSI_HPTIOP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_FCOE is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
@@ -702,6 +704,7 @@ CONFIG_NETDEV_1000=y
 # CONFIG_E1000E is not set
 # CONFIG_IP1000 is not set
 # CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -725,6 +728,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
 # CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
+# CONFIG_VXGE is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_NIU is not set
@@ -931,7 +935,6 @@ CONFIG_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1007,6 +1010,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -1028,6 +1032,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1073,8 +1082,13 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
@@ -1151,10 +1165,23 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 CONFIG_SH_STANDARD_BIOS=y
@@ -1256,6 +1283,7 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 26586c2d64cae371727a7f6524bf31164f6c2cb5..58bec61506fa3acdc17329a1274fba6328ff4960 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:07:39 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:49:32 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -39,6 +40,7 @@ CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
 # CONFIG_TASKSTATS is not set
@@ -66,7 +68,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -76,6 +77,7 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -94,6 +96,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_IOREMAP_PROT=y
@@ -101,6 +104,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -113,7 +118,6 @@ CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 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
 
@@ -159,6 +163,7 @@ CONFIG_CPU_SUBTYPE_SH7720=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -168,8 +173,6 @@ CONFIG_CPU_SUBTYPE_SH7720=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -813,6 +816,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 # CONFIG_EXT3_FS_XATTR is not set
 # CONFIG_EXT4_FS is not set
 CONFIG_JBD=y
@@ -830,6 +834,11 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -884,6 +893,7 @@ CONFIG_JFFS2_RTIME=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -965,6 +975,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 # CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_DETECT_HUNG_TASK is not set
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1000,6 +1011,7 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -1008,9 +1020,14 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 # CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1035,6 +1052,7 @@ CONFIG_DUMP_CODE=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 # CONFIG_CRYPTO is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 75178355d69ae1d776be3b28cbea555f1b957a84..2886fc84bc1cdd7e7f60e93077da12108aa0e11f 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:11:13 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:50:51 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -65,7 +66,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -74,6 +74,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -92,12 +93,15 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -105,7 +109,6 @@ 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
 
@@ -151,6 +154,7 @@ CONFIG_CPU_SH4=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 CONFIG_CPU_SUBTYPE_SH4_202=y
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -160,8 +164,6 @@ CONFIG_CPU_SUBTYPE_SH4_202=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -647,6 +649,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -668,6 +671,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -715,6 +723,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -802,10 +811,24 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -914,6 +937,7 @@ CONFIG_CRYPTO_DES=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index a8720f9c60472d040627a46ab050766715bb155e..8ecceb4bf27ecf5be03104908e00ae3f6aafe3b7 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:14:03 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:51:34 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -67,7 +68,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -76,6 +76,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -104,6 +105,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -115,7 +118,6 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -165,6 +167,7 @@ CONFIG_ARCH_SHMOBILE=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -174,8 +177,6 @@ CONFIG_ARCH_SHMOBILE=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 CONFIG_CPU_SUBTYPE_SH7722=y
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -577,6 +578,7 @@ CONFIG_SCSI_WAIT_SCAN=m
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
 # CONFIG_SCSI_OSD_INITIATOR is not set
@@ -873,7 +875,6 @@ CONFIG_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
@@ -1011,6 +1012,11 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1056,6 +1062,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
@@ -1105,11 +1112,25 @@ CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
 CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -1218,6 +1239,7 @@ CONFIG_CRYPTO_WORKQUEUE=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
index df2d177d5346e66caa1a278e53b8af3905fd219b..2b950728618278971ad32ee324aa1ee06d4a2351 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:16:48 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:52:19 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -40,6 +41,7 @@ CONFIG_LOCALVERSION=""
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
 # CONFIG_TASKSTATS is not set
@@ -76,6 +78,7 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -94,6 +97,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_IOREMAP_PROT=y
@@ -101,6 +105,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -113,7 +119,6 @@ CONFIG_MODVERSIONS=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -159,6 +164,7 @@ CONFIG_CPU_SUBTYPE_SH7709=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -168,8 +174,6 @@ CONFIG_CPU_SUBTYPE_SH7709=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -777,6 +781,11 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -831,6 +840,7 @@ CONFIG_JFFS2_RTIME=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -874,6 +884,9 @@ CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -914,6 +927,7 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -923,9 +937,14 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 # CONFIG_PREEMPT_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -950,6 +969,7 @@ CONFIG_DUMP_CODE=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 # CONFIG_CRYPTO is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 7def4df46ddb3294ba5903031038f61f0273ce47..943da63a385231cafd9bf0ab06fd3212ff7ba604 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:20:17 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:53:28 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -78,6 +79,7 @@ CONFIG_UID16=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -107,6 +109,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_BASE_SMALL=0
@@ -118,7 +122,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -165,6 +168,7 @@ CONFIG_CPU_SH4A=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 CONFIG_CPU_SUBTYPE_SH7780=y
@@ -174,8 +178,6 @@ CONFIG_CPU_SUBTYPE_SH7780=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -258,7 +260,7 @@ CONFIG_SH_R7780MP=y
 #
 CONFIG_SH_TMU=y
 CONFIG_SH_TIMER_IRQ=28
-CONFIG_SH_PCLK_FREQ=32000000
+CONFIG_SH_PCLK_FREQ=33333333
 # CONFIG_NO_HZ is not set
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
@@ -313,8 +315,6 @@ CONFIG_CMDLINE="console=ttySC0,115200 root=/dev/sda1"
 #
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCI_LEGACY=y
@@ -536,6 +536,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_MPT2SAS is not set
 # CONFIG_SCSI_HPTIOP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_FCOE is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
@@ -696,6 +697,7 @@ CONFIG_E1000=m
 # CONFIG_E1000E is not set
 # CONFIG_IP1000 is not set
 # CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -719,6 +721,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
 # CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
+# CONFIG_VXGE is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_NIU is not set
@@ -920,6 +923,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_F71805F is not set
 # CONFIG_SENSORS_F71882FG is not set
 # CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
@@ -1027,7 +1031,6 @@ CONFIG_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1120,6 +1123,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -1142,6 +1146,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 CONFIG_FUSE_FS=m
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1191,6 +1200,7 @@ CONFIG_MINIX_FS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -1279,6 +1289,9 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1316,6 +1329,7 @@ CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
 CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -1325,11 +1339,16 @@ CONFIG_TRACING=y
 # CONFIG_PREEMPT_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1449,6 +1468,7 @@ CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
index cb134ffc21185c64a40fd0f5a9c6a8d4b2e4e670..82658f6723980ceb48cfe6eecbc5f85399446f44 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:24:35 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:55:10 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -43,6 +44,7 @@ CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 # CONFIG_TASKSTATS is not set
@@ -78,6 +80,7 @@ CONFIG_UID16=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -108,6 +111,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -120,7 +125,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -168,6 +172,7 @@ CONFIG_CPU_SHX2=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -177,8 +182,6 @@ CONFIG_CPU_SUBTYPE_SH7785=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -266,7 +269,7 @@ CONFIG_SH_R7785RP=y
 #
 CONFIG_SH_TMU=y
 CONFIG_SH_TIMER_IRQ=28
-CONFIG_SH_PCLK_FREQ=50000000
+CONFIG_SH_PCLK_FREQ=33333333
 CONFIG_TICK_ONESHOT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -337,8 +340,6 @@ CONFIG_CMDLINE="console=ttySC0,115200 root=/dev/sda1"
 #
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 # CONFIG_PCI_LEGACY is not set
@@ -561,6 +562,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_MPT2SAS is not set
 # CONFIG_SCSI_HPTIOP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_FCOE is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
@@ -698,6 +700,7 @@ CONFIG_NETDEV_1000=y
 # CONFIG_E1000E is not set
 # CONFIG_IP1000 is not set
 # CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -721,6 +724,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
 # CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
+# CONFIG_VXGE is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_NIU is not set
@@ -948,6 +952,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_F71805F is not set
 # CONFIG_SENSORS_F71882FG is not set
 # CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
@@ -970,6 +975,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
 # CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SHT15 is not set
 # CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_DME1737 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
@@ -1109,7 +1115,6 @@ CONFIG_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1202,6 +1207,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -1224,6 +1230,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 CONFIG_FUSE_FS=m
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1273,6 +1284,7 @@ CONFIG_MINIX_FS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -1359,6 +1371,7 @@ CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 # CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_DETECT_HUNG_TASK is not set
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1401,6 +1414,7 @@ CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
 CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -1410,11 +1424,16 @@ CONFIG_TRACING=y
 # CONFIG_PREEMPT_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1534,6 +1553,7 @@ CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
index a037c744b798030f115fd9342de070b34370f68b..fa4395768d1921b467121ef134d4839720db2cfc 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:29:08 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:56:29 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -65,7 +66,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -74,6 +74,7 @@ CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -100,6 +101,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_RT_MUTEXES=y
 CONFIG_BASE_SMALL=0
@@ -110,7 +113,6 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -157,6 +159,7 @@ CONFIG_CPU_SUBTYPE_SH7201=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -166,8 +169,6 @@ CONFIG_CPU_SUBTYPE_SH7201=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -602,6 +603,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -651,8 +657,13 @@ CONFIG_JFFS2_RTIME=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 
 #
 # Partition Types
@@ -686,11 +697,24 @@ CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
 CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -705,6 +729,7 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 # CONFIG_CRYPTO is not set
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
index 9ae28e88426cfe56372ac305eda79e4877d26e1e..e3a65f819f0ac4c9b96192f378259a976b32b62e 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:30:34 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:57:06 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -39,6 +40,7 @@ CONFIG_LOCALVERSION=""
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 # CONFIG_TASKSTATS is not set
@@ -70,7 +72,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -80,6 +81,7 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -106,6 +108,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_RT_MUTEXES=y
 CONFIG_BASE_SMALL=0
@@ -116,7 +120,6 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -163,6 +166,7 @@ CONFIG_CPU_SUBTYPE_SH7203=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -172,8 +176,6 @@ CONFIG_CPU_SUBTYPE_SH7203=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -750,15 +752,17 @@ CONFIG_USB_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
+# CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
+# CONFIG_HID_KYE is not set
 CONFIG_HID_GYRATION=y
+# CONFIG_HID_KENSINGTON is not set
 CONFIG_HID_LOGITECH=y
 # CONFIG_LOGITECH_FF is not set
 # CONFIG_LOGIRUMBLEPAD2_FF is not set
@@ -874,6 +878,7 @@ CONFIG_LEDS_CLASS=y
 # LED drivers
 #
 CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
 
 #
 # LED Triggers
@@ -882,6 +887,7 @@ CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+# CONFIG_LEDS_TRIGGER_GPIO is not set
 CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
 
 #
@@ -950,6 +956,11 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -989,8 +1000,13 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
@@ -1033,6 +1049,9 @@ CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1076,6 +1095,7 @@ CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
 CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -1083,11 +1103,16 @@ CONFIG_TRACING=y
 # CONFIG_FUNCTION_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1111,6 +1136,7 @@ CONFIG_DUMP_CODE=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 # CONFIG_CRYPTO is not set
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
index c0f741af6da81f4cb6008d0a6b8fb30d7a9ea0de..a4a59f6205abdb204a95e933b7ff0742aaf5d74d 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:33:25 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:58:13 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -70,6 +71,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -99,6 +101,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -110,7 +114,6 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -156,6 +159,7 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -165,8 +169,6 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -302,8 +304,6 @@ CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1 earlyprintk=se
 #
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCI_LEGACY=y
@@ -513,6 +513,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_MPT2SAS is not set
 # CONFIG_SCSI_HPTIOP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_FCOE is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
@@ -672,6 +673,7 @@ CONFIG_NETDEV_1000=y
 # CONFIG_E1000E is not set
 # CONFIG_IP1000 is not set
 # CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -695,6 +697,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
 # CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
+# CONFIG_VXGE is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_NIU is not set
@@ -793,6 +796,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_SH_SCI=y
 CONFIG_SERIAL_SH_SCI_NR_UARTS=1
 CONFIG_SERIAL_SH_SCI_CONSOLE=y
@@ -1079,15 +1083,17 @@ CONFIG_USB_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
+# CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
+# CONFIG_HID_KYE is not set
 CONFIG_HID_GYRATION=y
+# CONFIG_HID_KENSINGTON is not set
 CONFIG_HID_LOGITECH=y
 # CONFIG_LOGITECH_FF is not set
 # CONFIG_LOGIRUMBLEPAD2_FF is not set
@@ -1290,6 +1296,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1337,6 +1348,7 @@ CONFIG_MINIX_FS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
@@ -1417,11 +1429,25 @@ CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
 CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -1524,6 +1550,7 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
index 8feef629e49c00fc8fe71dd5dbaa55cf1823534e..a860435b8847a3dcaeef804423811c47dfba31bf 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:34:12 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:59:01 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -70,6 +71,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -99,6 +101,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -110,7 +114,6 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -156,6 +159,7 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -165,8 +169,6 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -302,8 +304,6 @@ CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1 earlyprintk=se
 #
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCI_LEGACY=y
@@ -424,7 +424,92 @@ CONFIG_FIRMWARE_IN_KERNEL=y
 CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_SYS_HYPERVISOR is not set
 # CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_BLKDEVS is not set
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
@@ -513,6 +598,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_MPT2SAS is not set
 # CONFIG_SCSI_HPTIOP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_FCOE is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
@@ -672,6 +758,7 @@ CONFIG_NETDEV_1000=y
 # CONFIG_E1000E is not set
 # CONFIG_IP1000 is not set
 # CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -695,6 +782,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
 # CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
+# CONFIG_VXGE is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_NIU is not set
@@ -793,6 +881,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_SH_SCI=y
 CONFIG_SERIAL_SH_SCI_NR_UARTS=1
 CONFIG_SERIAL_SH_SCI_CONSOLE=y
@@ -1079,15 +1168,17 @@ CONFIG_USB_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
+# CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
+# CONFIG_HID_KYE is not set
 CONFIG_HID_GYRATION=y
+# CONFIG_HID_KENSINGTON is not set
 CONFIG_HID_LOGITECH=y
 # CONFIG_LOGITECH_FF is not set
 # CONFIG_LOGIRUMBLEPAD2_FF is not set
@@ -1290,6 +1381,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1337,6 +1433,7 @@ CONFIG_MINIX_FS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
@@ -1417,11 +1514,25 @@ CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
 CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -1524,6 +1635,7 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
index 739e2299ae80de0b05f249833b214e5db36c4586..a629b79a184400e8a27c420a2f917be6fb9bfb16 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:34:43 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 12:59:32 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -41,6 +42,7 @@ CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 # CONFIG_TASKSTATS is not set
@@ -73,6 +75,7 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -93,6 +96,7 @@ CONFIG_COMPAT_BRK=y
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_IOREMAP_PROT=y
@@ -100,6 +104,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -112,7 +118,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_BLOCK=y
 CONFIG_LBD=y
-# CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -159,6 +164,7 @@ CONFIG_CPU_SH4A=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 CONFIG_CPU_SUBTYPE_SH7780=y
@@ -168,8 +174,6 @@ CONFIG_CPU_SUBTYPE_SH7780=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -310,8 +314,6 @@ CONFIG_CMDLINE="mem=128M console=tty0 console=ttySC0,115200 ip=bootp root=/dev/n
 #
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 # CONFIG_PCI_LEGACY is not set
@@ -646,6 +648,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_MPT2SAS is not set
 # CONFIG_SCSI_HPTIOP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_FCOE is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
@@ -1091,15 +1094,17 @@ CONFIG_USB_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
+# CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
+# CONFIG_HID_KYE is not set
 CONFIG_HID_GYRATION=y
+# CONFIG_HID_KENSINGTON is not set
 CONFIG_HID_LOGITECH=y
 # CONFIG_LOGITECH_FF is not set
 # CONFIG_LOGIRUMBLEPAD2_FF is not set
@@ -1257,6 +1262,7 @@ CONFIG_EXT2_FS_POSIX_ACL=y
 # CONFIG_EXT2_FS_SECURITY is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -1280,6 +1286,11 @@ CONFIG_AUTOFS4_FS=y
 # CONFIG_FUSE_FS is not set
 CONFIG_GENERIC_ACL=y
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1331,6 +1342,7 @@ CONFIG_MINIX_FS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -1418,6 +1430,9 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
 CONFIG_TIMER_STATS=y
@@ -1455,6 +1470,7 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -1464,9 +1480,14 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 # CONFIG_PREEMPT_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1580,6 +1601,7 @@ CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index d30e0a7ad9f17166ab2b339e2ac2a1367aa4e7d0..5caf85a3312dab68496039e6a3be3628df476760 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:39:37 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:01:02 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -40,6 +41,7 @@ CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 # CONFIG_TASKSTATS is not set
@@ -63,6 +65,7 @@ CONFIG_CGROUP_DEBUG=y
 CONFIG_CGROUP_NS=y
 # CONFIG_CGROUP_FREEZER is not set
 CONFIG_CGROUP_DEVICE=y
+# CONFIG_CPUSETS is not set
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_RESOURCE_COUNTERS=y
 CONFIG_CGROUP_MEM_RES_CTLR=y
@@ -80,7 +83,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -90,6 +92,7 @@ CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -116,6 +119,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_RT_MUTEXES=y
 CONFIG_BASE_SMALL=0
@@ -127,7 +132,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -174,6 +178,7 @@ CONFIG_CPU_SUBTYPE_SH7206=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -183,8 +188,6 @@ CONFIG_CPU_SUBTYPE_SH7206=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -745,6 +748,11 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -785,8 +793,13 @@ CONFIG_CRAMFS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -831,6 +844,9 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -869,6 +885,7 @@ CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
 CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -876,11 +893,16 @@ CONFIG_TRACING=y
 # CONFIG_FUNCTION_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -991,6 +1013,7 @@ CONFIG_CRYPTO_LZO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
index fbb72d029e685259a8c96747f49fe2df1897b6a8..004d531716dcae143b07392127583a660300534d 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:42:00 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:01:44 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -40,6 +41,7 @@ CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
@@ -73,6 +75,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -91,6 +94,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_IOREMAP_PROT=y
@@ -98,6 +102,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_BASE_SMALL=0
@@ -109,7 +115,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -158,6 +163,7 @@ CONFIG_ARCH_SHMOBILE=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -167,8 +173,6 @@ CONFIG_ARCH_SHMOBILE=y
 CONFIG_CPU_SUBTYPE_SH7343=y
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -769,6 +773,7 @@ CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
 # CONFIG_SOC_CAMERA is not set
 CONFIG_V4L_USB_DRIVERS=y
 # CONFIG_USB_VIDEO_CLASS is not set
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
 CONFIG_USB_GSPCA=m
 # CONFIG_USB_M5602 is not set
 # CONFIG_USB_STV06XX is not set
@@ -800,6 +805,7 @@ CONFIG_USB_GSPCA=m
 # CONFIG_VIDEO_PVRUSB2 is not set
 # CONFIG_VIDEO_HDPVR is not set
 # CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_CX231XX is not set
 # CONFIG_VIDEO_USBVISION is not set
 # CONFIG_USB_VICAM is not set
 # CONFIG_USB_IBMCAM is not set
@@ -813,6 +819,7 @@ CONFIG_USB_GSPCA=m
 # CONFIG_USB_STV680 is not set
 # CONFIG_USB_ZC0301 is not set
 # CONFIG_USB_PWC is not set
+CONFIG_USB_PWC_INPUT_EVDEV=y
 # CONFIG_USB_ZR364XX is not set
 # CONFIG_USB_STKWEBCAM is not set
 # CONFIG_USB_S2255 is not set
@@ -914,15 +921,17 @@ CONFIG_USB_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
+# CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
+# CONFIG_HID_KYE is not set
 CONFIG_HID_GYRATION=y
+# CONFIG_HID_KENSINGTON is not set
 CONFIG_HID_LOGITECH=y
 # CONFIG_LOGITECH_FF is not set
 # CONFIG_LOGIRUMBLEPAD2_FF is not set
@@ -1050,6 +1059,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -1070,6 +1080,11 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1125,6 +1140,7 @@ CONFIG_CRAMFS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -1174,10 +1190,23 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -1279,6 +1308,7 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 125304e80f5783947dbffe73f17f854735fe551d..edbece52afc1c96728110b873a903773a56fe73f 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:44:53 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:02:32 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -61,6 +62,7 @@ CONFIG_EMBEDDED=y
 # CONFIG_UID16 is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -78,11 +80,14 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_BASE_SMALL=1
@@ -134,6 +139,7 @@ CONFIG_CPU_SUBTYPE_SH7619=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -143,8 +149,6 @@ CONFIG_CPU_SUBTYPE_SH7619=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -513,7 +517,6 @@ CONFIG_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
@@ -563,6 +566,11 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -601,8 +609,13 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 
 #
 # Partition Types
@@ -630,10 +643,21 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -647,6 +671,7 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 # CONFIG_CRYPTO is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 0308abf5238494a710751d7ab73f9739aeada17f..bae161c66835726a846490c1d48b2c0917120682 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:45:56 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:02:52 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -62,7 +63,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -70,6 +70,7 @@ CONFIG_EMBEDDED=y
 CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -88,12 +89,15 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -150,6 +154,7 @@ CONFIG_CPU_SUBTYPE_SH7705=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -159,8 +164,6 @@ CONFIG_CPU_SUBTYPE_SH7705=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -698,7 +701,6 @@ CONFIG_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
@@ -751,6 +753,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -804,6 +811,7 @@ CONFIG_JFFS2_RTIME=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
@@ -847,10 +855,23 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -949,6 +970,7 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index a8c24b7034893627f315924afe4e680b3b66e9bb..330043f3c3164a24203dd9977a21ba6f5cf9a47d 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:48:18 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:03:27 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -38,6 +39,7 @@ CONFIG_LOCALVERSION=""
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 # CONFIG_TASKSTATS is not set
@@ -69,6 +71,7 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 # CONFIG_BUG is not set
@@ -87,6 +90,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_IOREMAP_PROT=y
@@ -94,6 +98,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -105,7 +111,6 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -151,6 +156,7 @@ CONFIG_CPU_SUBTYPE_SH7712=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -160,8 +166,6 @@ CONFIG_CPU_SUBTYPE_SH7712=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -585,6 +589,7 @@ CONFIG_SCSI_WAIT_SCAN=m
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
 # CONFIG_SCSI_OSD_INITIATOR is not set
@@ -812,6 +817,7 @@ CONFIG_EXT2_FS_POSIX_ACL=y
 CONFIG_EXT2_FS_SECURITY=y
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -832,6 +838,11 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -887,6 +898,7 @@ CONFIG_CRAMFS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
@@ -927,6 +939,7 @@ CONFIG_FRAME_WARN=1024
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 # CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_DETECT_HUNG_TASK is not set
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -961,6 +974,7 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -969,9 +983,14 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 # CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1090,6 +1109,7 @@ CONFIG_CRYPTO_DEFLATE=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 4b79c2567dc8446518c7c70b41042aa8cc34cb8a..56478918440da042ba1c4b26ae27bae4bbf246d5 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:51:44 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:04:19 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -38,6 +39,7 @@ CONFIG_LOCALVERSION=""
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 # CONFIG_TASKSTATS is not set
@@ -73,6 +75,7 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 # CONFIG_BUG is not set
@@ -91,6 +94,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_IOREMAP_PROT=y
@@ -98,6 +102,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -109,7 +115,6 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -155,6 +160,7 @@ CONFIG_CPU_SUBTYPE_SH7721=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -164,8 +170,6 @@ CONFIG_CPU_SUBTYPE_SH7721=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -776,15 +780,17 @@ CONFIG_USB_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
+# CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
+# CONFIG_HID_KYE is not set
 CONFIG_HID_GYRATION=y
+# CONFIG_HID_KENSINGTON is not set
 CONFIG_HID_LOGITECH=y
 # CONFIG_LOGITECH_FF is not set
 # CONFIG_LOGIRUMBLEPAD2_FF is not set
@@ -943,6 +949,7 @@ CONFIG_EXT2_FS_POSIX_ACL=y
 CONFIG_EXT2_FS_SECURITY=y
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -963,6 +970,11 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1021,6 +1033,7 @@ CONFIG_CRAMFS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 # CONFIG_NETWORK_FILESYSTEMS is not set
 
 #
@@ -1085,6 +1098,7 @@ CONFIG_FRAME_WARN=1024
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 # CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_DETECT_HUNG_TASK is not set
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1119,6 +1133,7 @@ CONFIG_FRAME_POINTER=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -1127,9 +1142,14 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 # CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1248,6 +1268,7 @@ CONFIG_CRYPTO_DEFLATE=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 82bdaac45fb51b3a290993ba1806b34ef2acece7..726fdbdb2807f1d0752ec05aa3083765d8cf6e6b 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:55:10 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:05:29 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -69,7 +70,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -78,6 +78,7 @@ CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -97,6 +98,7 @@ CONFIG_COMPAT_BRK=y
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 CONFIG_PROFILING=y
+# CONFIG_MARKERS is not set
 # CONFIG_OPROFILE is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
@@ -105,6 +107,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -117,7 +121,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -167,6 +170,7 @@ CONFIG_ARCH_SHMOBILE=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -176,8 +180,6 @@ CONFIG_ARCH_SHMOBILE=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 CONFIG_CPU_SUBTYPE_SH7722=y
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -486,6 +488,7 @@ CONFIG_SCSI_WAIT_SCAN=m
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
 # CONFIG_SCSI_OSD_INITIATOR is not set
@@ -692,7 +695,6 @@ CONFIG_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
@@ -766,6 +768,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -788,6 +791,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -832,6 +840,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
@@ -872,11 +881,25 @@ CONFIG_DEBUG_FS=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 CONFIG_SH_STANDARD_BIOS=y
@@ -977,6 +1000,7 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
diff --git a/arch/sh/configs/se7724_defconfig b/arch/sh/configs/se7724_defconfig
new file mode 100644 (file)
index 0000000..96d2587
--- /dev/null
@@ -0,0 +1,1552 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc6
+# Tue May 26 13:18:09 2009
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
+CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_SYS_SUPPORTS_CMT=y
+CONFIG_SYS_SUPPORTS_TMU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_ARCH_HAS_DEFAULT_IDLE=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 is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD 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=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# System type
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+CONFIG_CPU_SHX2=y
+CONFIG_ARCH_SHMOBILE=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7201 is not set
+# CONFIG_CPU_SUBTYPE_SH7203 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7263 is not set
+# CONFIG_CPU_SUBTYPE_MXG is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
+# CONFIG_CPU_SUBTYPE_SH7721 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_SH7723 is not set
+CONFIG_CPU_SUBTYPE_SH7724=y
+# CONFIG_CPU_SUBTYPE_SH7763 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SH7786 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+# CONFIG_CPU_SUBTYPE_SH7366 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x08000000
+CONFIG_29BIT=y
+# CONFIG_X2TLB is not set
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+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_SPARSEMEM_STATIC=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+
+#
+# Cache configuration
+#
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH_STORE_QUEUES is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_PTEA=y
+CONFIG_CPU_HAS_FPU=y
+
+#
+# Board support
+#
+CONFIG_SOLUTION_ENGINE=y
+CONFIG_SH_7724_SOLUTION_ENGINE=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TIMER_TMU=y
+# CONFIG_SH_TIMER_CMT is not set
+CONFIG_SH_PCLK_FREQ=33333333
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_SECCOMP=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_GUSA=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_ENTRY_OFFSET=0x00001000
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=tty1 console=ttySC3,115200 root=/dev/nfs ip=dhcp memchunk.vpu=4m"
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+# CONFIG_CPU_IDLE is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+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=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP 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=y
+CONFIG_INET_TCP_DIAG=y
+# 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_PHONET 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_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_LIB80211 is not set
+# CONFIG_MAC80211 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_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG 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_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+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=y
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+CONFIG_COMPAT_NET_DEV_OPS=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH 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=y
+# CONFIG_MDIO_GPIO is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_STNIC is not set
+CONFIG_SMC91X=y
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_GPIO is not set
+CONFIG_KEYBOARD_SH_KEYSC=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=6
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_SH_MOBILE=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+# CONFIG_SPI_GPIO is not set
+# CONFIG_SPI_SH_SCI is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# 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_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+# CONFIG_VIDEO_ALLOW_V4L1 is not set
+CONFIG_VIDEO_V4L1_COMPAT=y
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=y
+CONFIG_MEDIA_TUNER_TDA8290=y
+CONFIG_MEDIA_TUNER_TDA9887=y
+CONFIG_MEDIA_TUNER_TEA5761=y
+CONFIG_MEDIA_TUNER_TEA5767=y
+CONFIG_MEDIA_TUNER_MT20XX=y
+CONFIG_MEDIA_TUNER_XC2028=y
+CONFIG_MEDIA_TUNER_XC5000=y
+CONFIG_MEDIA_TUNER_MC44S803=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF_DMA_CONTIG=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+CONFIG_SOC_CAMERA=y
+# CONFIG_SOC_CAMERA_MT9M001 is not set
+# CONFIG_SOC_CAMERA_MT9M111 is not set
+# CONFIG_SOC_CAMERA_MT9T031 is not set
+# CONFIG_SOC_CAMERA_MT9V022 is not set
+# CONFIG_SOC_CAMERA_TW9910 is not set
+# CONFIG_SOC_CAMERA_PLATFORM is not set
+CONFIG_SOC_CAMERA_OV772X=y
+CONFIG_VIDEO_SH_MOBILE_CEU=y
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_USB_VIDEO_CLASS is not set
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+CONFIG_USB_GSPCA=m
+# CONFIG_USB_M5602 is not set
+# CONFIG_USB_STV06XX is not set
+# CONFIG_USB_GSPCA_CONEX is not set
+# CONFIG_USB_GSPCA_ETOMS is not set
+# CONFIG_USB_GSPCA_FINEPIX is not set
+# CONFIG_USB_GSPCA_MARS is not set
+# CONFIG_USB_GSPCA_MR97310A is not set
+# CONFIG_USB_GSPCA_OV519 is not set
+# CONFIG_USB_GSPCA_OV534 is not set
+# CONFIG_USB_GSPCA_PAC207 is not set
+# CONFIG_USB_GSPCA_PAC7311 is not set
+# CONFIG_USB_GSPCA_SONIXB is not set
+# CONFIG_USB_GSPCA_SONIXJ is not set
+# CONFIG_USB_GSPCA_SPCA500 is not set
+# CONFIG_USB_GSPCA_SPCA501 is not set
+# CONFIG_USB_GSPCA_SPCA505 is not set
+# CONFIG_USB_GSPCA_SPCA506 is not set
+# CONFIG_USB_GSPCA_SPCA508 is not set
+# CONFIG_USB_GSPCA_SPCA561 is not set
+# CONFIG_USB_GSPCA_SQ905 is not set
+# CONFIG_USB_GSPCA_SQ905C is not set
+# CONFIG_USB_GSPCA_STK014 is not set
+# CONFIG_USB_GSPCA_SUNPLUS is not set
+# CONFIG_USB_GSPCA_T613 is not set
+# CONFIG_USB_GSPCA_TV8532 is not set
+# CONFIG_USB_GSPCA_VC032X is not set
+# CONFIG_USB_GSPCA_ZC3XX is not set
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_HDPVR is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_CX231XX is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_ZC0301 is not set
+CONFIG_USB_PWC_INPUT_EVDEV=y
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_S2255 is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=y
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_SH_MOBILE_LCDC=y
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+CONFIG_LOGO_SUPERH_CLUT224=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+CONFIG_USB_R8A66597_HCD=y
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_SPI=y
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+CONFIG_RTC_DRV_PCF8563=y
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_SH is not set
+# CONFIG_RTC_DRV_GENERIC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+CONFIG_UIO=y
+# CONFIG_UIO_PDRV is not set
+CONFIG_UIO_PDRV_GENIRQ=y
+# CONFIG_UIO_SMX is not set
+# CONFIG_UIO_SERCOS3 is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_UBIFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_CODEPAGE_932=y
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+# 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 is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE 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=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+CONFIG_CRC7=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index ceef6d9138ee2d9606edd2ee8b692d20059942a0..ed1a1230f6362025e9888736779e9ecdf5524281 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:57:31 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:06:02 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -70,6 +71,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -88,6 +90,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_IOREMAP_PROT=y
@@ -95,6 +98,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -106,7 +111,6 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -152,6 +156,7 @@ CONFIG_CPU_SUBTYPE_SH7750=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -161,8 +166,6 @@ CONFIG_CPU_SUBTYPE_SH7750=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -553,6 +556,7 @@ CONFIG_SCSI_WAIT_SCAN=m
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
 # CONFIG_SCSI_OSD_INITIATOR is not set
@@ -774,6 +778,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -829,6 +838,7 @@ CONFIG_JFFS2_RTIME=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
@@ -886,10 +896,23 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -989,6 +1012,7 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 67fc26b3a7d0995d1a58aa87de909eebb9be0e0a..55f3b788e0cbdd63d052c2ecb81e9d702d7fe298 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 18:59:59 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:06:44 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -65,7 +66,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -74,6 +74,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -92,6 +93,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_IOREMAP_PROT=y
@@ -99,6 +101,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -110,7 +114,6 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -156,6 +159,7 @@ CONFIG_CPU_SUBTYPE_SH7751=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -165,8 +169,6 @@ CONFIG_CPU_SUBTYPE_SH7751=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -741,6 +743,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -796,6 +803,7 @@ CONFIG_JFFS2_RTIME=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
@@ -833,10 +841,23 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -936,6 +957,7 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index ebce23cc2ad831a29db8d6579533c67d048b2e74..c4f0af32efa97148031c45f38a9dd4930410a4db 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 19:02:05 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:07:14 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -67,6 +68,7 @@ CONFIG_EMBEDDED=y
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
 # CONFIG_KALLSYMS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -86,12 +88,15 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -103,7 +108,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
 #
@@ -149,6 +153,7 @@ CONFIG_CPU_SH4A=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 CONFIG_CPU_SUBTYPE_SH7780=y
@@ -158,8 +163,6 @@ CONFIG_CPU_SUBTYPE_SH7780=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -285,8 +288,6 @@ CONFIG_CMDLINE="console=ttySC0.115200 root=/dev/sda1"
 #
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCI_LEGACY=y
@@ -558,6 +559,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_MPT2SAS is not set
 # CONFIG_SCSI_HPTIOP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_FCOE is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
@@ -957,15 +959,17 @@ CONFIG_USB_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
+# CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
+# CONFIG_HID_KYE is not set
 CONFIG_HID_GYRATION=y
+# CONFIG_HID_KENSINGTON is not set
 CONFIG_HID_LOGITECH=y
 # CONFIG_LOGITECH_FF is not set
 # CONFIG_LOGIRUMBLEPAD2_FF is not set
@@ -1121,6 +1125,10 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1245,11 +1253,24 @@ CONFIG_DEBUG_FS=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -1345,6 +1366,7 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 6fcdb090cf32203cb424cecb0f15663d02ae0b21..f9c6e51dc0b0a33f2fe8b7a42e0cd8c3f08998c7 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 19:04:59 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:07:56 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -41,6 +42,7 @@ CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 # CONFIG_TASKSTATS is not set
@@ -67,7 +69,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -76,6 +77,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -105,6 +107,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -117,7 +121,6 @@ CONFIG_MODVERSIONS=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -163,6 +166,7 @@ CONFIG_CPU_SUBTYPE_SH7751=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -172,8 +176,6 @@ CONFIG_CPU_SUBTYPE_SH7751=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -300,8 +302,6 @@ CONFIG_CMDLINE="console=ttySC1,115200 mem=64M root=/dev/nfs"
 #
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCI_LEGACY=y
@@ -562,6 +562,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_MPT2SAS is not set
 # CONFIG_SCSI_HPTIOP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_FCOE is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
@@ -656,6 +657,7 @@ CONFIG_NETDEV_1000=y
 # CONFIG_E1000E is not set
 # CONFIG_IP1000 is not set
 # CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -679,6 +681,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
 # CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
+# CONFIG_VXGE is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_NIU is not set
@@ -887,7 +890,6 @@ CONFIG_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
@@ -929,6 +931,7 @@ CONFIG_EXT2_FS_XATTR=y
 # CONFIG_EXT2_FS_SECURITY is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -951,6 +954,11 @@ CONFIG_AUTOFS_FS=y
 CONFIG_AUTOFS4_FS=y
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1001,6 +1009,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -1112,11 +1121,26 @@ CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
 CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 CONFIG_SH_STANDARD_BIOS=y
@@ -1228,6 +1252,7 @@ CONFIG_CRYPTO_DEFLATE=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
index 1ab37c01da6e9201b1609ce6b32f1e5fba58ff22..48b58098cf841510228b6b3f16782bde60b46614 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 19:09:01 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:09:16 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -39,6 +40,7 @@ CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
@@ -72,6 +74,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -90,6 +93,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_IOREMAP_PROT=y
@@ -97,6 +101,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_BASE_SMALL=0
@@ -108,7 +114,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -154,6 +159,7 @@ CONFIG_CPU_SUBTYPE_SH7710=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -163,8 +169,6 @@ CONFIG_CPU_SUBTYPE_SH7710=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -728,7 +732,6 @@ CONFIG_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
@@ -779,6 +782,11 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -834,6 +842,7 @@ CONFIG_JFFS2_RTIME=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
@@ -871,11 +880,24 @@ CONFIG_DEBUG_FS=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -975,6 +997,7 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
diff --git a/arch/sh/configs/sh7724_generic_defconfig b/arch/sh/configs/sh7724_generic_defconfig
new file mode 100644 (file)
index 0000000..ec8f18c
--- /dev/null
@@ -0,0 +1,707 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:09:47 2009
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
+CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_GPIO is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_SYS_SUPPORTS_CMT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_ARCH_HAS_DEFAULT_IDLE=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+
+#
+# RCU Subsystem
+#
+# CONFIG_CLASSIC_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_NS is not set
+# CONFIG_CGROUP_FREEZER is not set
+# CONFIG_CGROUP_DEVICE is not set
+# CONFIG_CPUSETS is not set
+# CONFIG_CGROUP_CPUACCT is not set
+# CONFIG_RESOURCE_COUNTERS is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+# CONFIG_UID16 is not set
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=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_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_FREEZER=y
+
+#
+# System type
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+CONFIG_CPU_SHX2=y
+CONFIG_ARCH_SHMOBILE=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7201 is not set
+# CONFIG_CPU_SUBTYPE_SH7203 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7263 is not set
+# CONFIG_CPU_SUBTYPE_MXG is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
+# CONFIG_CPU_SUBTYPE_SH7721 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_SH7723 is not set
+CONFIG_CPU_SUBTYPE_SH7724=y
+# CONFIG_CPU_SUBTYPE_SH7763 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SH7786 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+# CONFIG_CPU_SUBTYPE_SH7366 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_29BIT=y
+# CONFIG_X2TLB is not set
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_ENTRY_OFFSET=0x00001000
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_STATIC=y
+
+#
+# Memory hotplug is currently incompatible with Software Suspend
+#
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+
+#
+# Cache configuration
+#
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH_STORE_QUEUES is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_PTEA=y
+CONFIG_CPU_HAS_FPU=y
+
+#
+# Board support
+#
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_CMT=y
+CONFIG_SH_TIMER_IRQ=16
+CONFIG_SH_PCLK_FREQ=41666666
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_SH_CPU_FREQ=y
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_HEARTBEAT is not set
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_SCHED_HRTICK=y
+CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
+CONFIG_KEXEC_JUMP=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_GUSA=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_HIBERNATION=y
+CONFIG_PM_STD_PARTITION=""
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR 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_RAM is not set
+# CONFIG_CDROM_PKTCDVD 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_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 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=6
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_SH_MOBILE=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+# 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_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV 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_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SH=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+CONFIG_UIO=y
+# CONFIG_UIO_PDRV is not set
+CONFIG_UIO_PDRV_GENIRQ=y
+# CONFIG_UIO_SMX is not set
+# CONFIG_UIO_SERCOS3 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_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
+
+#
+# Caches
+#
+# CONFIG_FSCACHE 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 is not set
+# CONFIG_SYSFS is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# 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=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_MORE_COMPILE_OPTIONS is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+CONFIG_BINARY_PRINTF=y
+
+#
+# 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_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index c79bb84ec305136f57728b86f84071e2dd142576..f77bc7998d2fb1039aca2415a45ebc50c0e225da 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 19:10:57 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:10:12 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -78,6 +79,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -106,6 +108,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -117,7 +121,6 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -164,6 +167,7 @@ CONFIG_CPU_SH4A=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 CONFIG_CPU_SUBTYPE_SH7763=y
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -173,8 +177,6 @@ CONFIG_CPU_SUBTYPE_SH7763=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -555,6 +557,7 @@ CONFIG_SCSI_WAIT_SCAN=m
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
 # CONFIG_SCSI_OSD_INITIATOR is not set
@@ -941,6 +944,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -964,6 +968,11 @@ CONFIG_AUTOFS4_FS=y
 # CONFIG_FUSE_FS is not set
 CONFIG_GENERIC_ACL=y
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1012,6 +1021,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
@@ -1100,11 +1110,25 @@ CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
 CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -1204,6 +1228,7 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
diff --git a/arch/sh/configs/sh7770_generic_defconfig b/arch/sh/configs/sh7770_generic_defconfig
new file mode 100644 (file)
index 0000000..d6489b4
--- /dev/null
@@ -0,0 +1,700 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc4
+# Tue May 12 14:48:21 2009
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
+CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_GPIO is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_ARCH_SUSPEND_POSSIBLE is not set
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_SYS_SUPPORTS_TMU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_ARCH_HAS_DEFAULT_IDLE=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+
+#
+# RCU Subsystem
+#
+# CONFIG_CLASSIC_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_NS is not set
+# CONFIG_CGROUP_FREEZER is not set
+# CONFIG_CGROUP_DEVICE is not set
+# CONFIG_CPUSETS is not set
+# CONFIG_CGROUP_CPUACCT is not set
+# CONFIG_RESOURCE_COUNTERS is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+# CONFIG_UID16 is not set
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=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_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_FREEZER=y
+
+#
+# System type
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7201 is not set
+# CONFIG_CPU_SUBTYPE_SH7203 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7263 is not set
+# CONFIG_CPU_SUBTYPE_MXG is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
+# CONFIG_CPU_SUBTYPE_SH7721 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
+# CONFIG_CPU_SUBTYPE_SH7763 is not set
+CONFIG_CPU_SUBTYPE_SH7770=y
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SH7786 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+# CONFIG_CPU_SUBTYPE_SH7366 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_29BIT=y
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_STATIC=y
+
+#
+# Memory hotplug is currently incompatible with Software Suspend
+#
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+
+#
+# Cache configuration
+#
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH_STORE_QUEUES is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_FPU=y
+
+#
+# Board support
+#
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+CONFIG_SH_PCLK_FREQ=41666666
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_SH_CPU_FREQ=y
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_HEARTBEAT is not set
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_SCHED_HRTICK=y
+CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
+CONFIG_KEXEC_JUMP=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_GUSA=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_ENTRY_OFFSET=0x00001000
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_HIBERNATION=y
+CONFIG_PM_STD_PARTITION=""
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR 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_RAM is not set
+# CONFIG_CDROM_PKTCDVD 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_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 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=6
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_SH_MOBILE=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+# 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_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV 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_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SH=y
+# CONFIG_RTC_DRV_GENERIC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+CONFIG_UIO=y
+# CONFIG_UIO_PDRV is not set
+CONFIG_UIO_PDRV_GENIRQ=y
+# CONFIG_UIO_SMX is not set
+# CONFIG_UIO_SERCOS3 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_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
+
+#
+# Caches
+#
+# CONFIG_FSCACHE 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 is not set
+# CONFIG_SYSFS is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# 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=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+CONFIG_BINARY_PRINTF=y
+
+#
+# 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_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index a6cf4505741ca43554f5acd446fe15c51cafd8e3..1c55b800d1240999df420e8d93e0249668aa26d5 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 19:12:18 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:10:53 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -79,6 +80,7 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -98,6 +100,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 CONFIG_PROFILING=y
+# CONFIG_MARKERS is not set
 # CONFIG_OPROFILE is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
@@ -106,6 +109,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -118,7 +123,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -166,6 +170,7 @@ CONFIG_CPU_SHX2=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -175,8 +180,6 @@ CONFIG_CPU_SUBTYPE_SH7785=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -310,8 +313,6 @@ CONFIG_BOOT_LINK_OFFSET=0x00800000
 #
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCI_LEGACY=y
@@ -672,6 +673,7 @@ CONFIG_NETDEV_1000=y
 # CONFIG_E1000E is not set
 # CONFIG_IP1000 is not set
 # CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -1009,15 +1011,17 @@ CONFIG_USB_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
+# CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
+# CONFIG_HID_KYE is not set
 CONFIG_HID_GYRATION=y
+# CONFIG_HID_KENSINGTON is not set
 CONFIG_HID_LOGITECH=y
 # CONFIG_LOGITECH_FF is not set
 # CONFIG_LOGIRUMBLEPAD2_FF is not set
@@ -1218,6 +1222,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -1239,6 +1244,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1289,6 +1299,7 @@ CONFIG_MINIX_FS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -1377,6 +1388,9 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1413,6 +1427,7 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -1422,9 +1437,14 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 # CONFIG_PREEMPT_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1542,6 +1562,7 @@ CONFIG_CRYPTO_DES=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index e4fac2efc055e5d7ef869ab755c870328d0bd8b7..4385fe97a780763011a4a3ec88e188febe55fc4b 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2
-# Wed Apr 22 19:17:56 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:11:48 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
@@ -307,8 +307,6 @@ CONFIG_BOOT_LINK_OFFSET=0x00800000
 #
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCI_LEGACY=y
index d695e906187484a23038c7c79c3590e07bcf63cb..4e120256ec638d34168016aeb12f7bf758023d0e 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 19:19:03 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:12:41 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -63,6 +64,7 @@ CONFIG_EMBEDDED=y
 # CONFIG_UID16 is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 # CONFIG_BUG is not set
@@ -81,12 +83,15 @@ CONFIG_COMPAT_BRK=y
 # CONFIG_SLUB is not set
 CONFIG_SLOB=y
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_BASE_SMALL=1
 # CONFIG_MODULES is not set
@@ -137,6 +142,7 @@ CONFIG_CPU_SUBTYPE_SH7706=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -146,8 +152,6 @@ CONFIG_CPU_SUBTYPE_SH7706=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -674,6 +678,11 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -718,6 +727,7 @@ CONFIG_CRAMFS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -762,10 +772,22 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 CONFIG_SH_STANDARD_BIOS=y
@@ -864,6 +886,7 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index e3651f5743996c419e92c7f7b8cc438e1d893490..c088144925faedfc3e4b4dc5bc7f5b35001501a9 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 19:20:54 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:13:12 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -42,6 +43,7 @@ CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 # CONFIG_TASKSTATS is not set
@@ -96,6 +98,7 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -126,6 +129,8 @@ CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_USE_GENERIC_SMP_HELPERS=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_RT_MUTEXES=y
 CONFIG_BASE_SMALL=0
@@ -138,7 +143,6 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_STOP_MACHINE=y
 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
 
@@ -186,6 +190,7 @@ CONFIG_CPU_SHX3=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -195,8 +200,6 @@ CONFIG_CPU_SUBTYPE_SHX3=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -553,6 +556,7 @@ CONFIG_SCSI_WAIT_SCAN=m
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
 # CONFIG_SCSI_OSD_INITIATOR is not set
@@ -646,6 +650,7 @@ CONFIG_DEVKMEM=y
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_SH_SCI=y
 CONFIG_SERIAL_SH_SCI_NR_UARTS=2
 CONFIG_SERIAL_SH_SCI_CONSOLE=y
@@ -985,6 +990,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -1007,6 +1013,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1051,6 +1062,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
@@ -1085,6 +1097,9 @@ CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1124,6 +1139,7 @@ CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
 CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -1133,11 +1149,16 @@ CONFIG_TRACING=y
 # CONFIG_PREEMPT_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1245,6 +1266,7 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
index 6960f60bf52e9b4e22f3866a5a9a707cb5f64a94..54a7a3c41f34f2b186bb05c0e3f097650e9dd867 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 19:21:39 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:14:00 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -64,7 +65,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -73,6 +73,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -92,12 +93,15 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -105,7 +109,6 @@ 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
 
@@ -151,6 +154,7 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -160,8 +164,6 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -295,8 +297,6 @@ CONFIG_BOOT_LINK_OFFSET=0x00800000
 #
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCI_LEGACY=y
@@ -762,6 +762,11 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -805,8 +810,13 @@ CONFIG_CRAMFS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
@@ -844,10 +854,23 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -862,6 +885,7 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 # CONFIG_CRYPTO is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 7ea639bc5936e37ab4399a6e0cbe3d7cd66c7686..dbe7e546f0bb63728aa1644188973790f7d08d45 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 19:23:31 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:14:33 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -61,7 +62,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -70,6 +70,7 @@ CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -88,6 +89,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_IOREMAP_PROT=y
@@ -95,6 +97,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -107,7 +111,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -153,6 +156,7 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -162,8 +166,6 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -505,6 +507,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -547,8 +554,13 @@ CONFIG_CRAMFS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 
 #
 # Partition Types
@@ -577,10 +589,24 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -595,6 +621,7 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 # CONFIG_CRYPTO is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index bbeb4c6ebb95576031c35d757e02bd22e0341468..8ca94ef74278c35d29da153739cecba331249e91 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 19:24:55 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:14:55 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -40,6 +41,7 @@ CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
@@ -66,7 +68,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -76,6 +77,7 @@ CONFIG_UID16=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -95,6 +97,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_IOREMAP_PROT=y
@@ -102,6 +105,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -114,7 +119,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -160,6 +164,7 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -169,8 +174,6 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -305,8 +308,6 @@ CONFIG_CMDLINE="console=ttySC1,38400N81 root=/dev/nfs ip=:::::eth1:autoconf rw"
 #
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 CONFIG_PCI_LEGACY=y
@@ -789,6 +790,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_MPT2SAS is not set
 # CONFIG_SCSI_HPTIOP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_FCOE is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
@@ -906,6 +908,7 @@ CONFIG_NETDEV_1000=y
 # CONFIG_E1000E is not set
 # CONFIG_IP1000 is not set
 # CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -929,6 +932,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
 # CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
+# CONFIG_VXGE is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_NIU is not set
@@ -1182,7 +1186,6 @@ CONFIG_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1393,6 +1396,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 # CONFIG_EXT3_FS_XATTR is not set
 # CONFIG_EXT4_FS is not set
 CONFIG_JBD=y
@@ -1418,6 +1422,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 CONFIG_FUSE_FS=m
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1467,8 +1476,13 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -1576,6 +1590,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 # CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_DETECT_HUNG_TASK is not set
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1610,6 +1625,7 @@ CONFIG_SCHED_DEBUG=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -1618,9 +1634,14 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 # CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1741,6 +1762,7 @@ CONFIG_CRYPTO_DEFLATE=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 34f5192a32411f5d40547fb663285363cc451109..bfb4d9806892e452d5eeadb938c34e9eab283a22 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 19:30:27 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 13:17:05 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -69,7 +70,6 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -78,6 +78,7 @@ CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -97,6 +98,7 @@ CONFIG_COMPAT_BRK=y
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 CONFIG_PROFILING=y
+# CONFIG_MARKERS is not set
 # CONFIG_OPROFILE is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
@@ -105,6 +107,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -117,7 +121,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -167,6 +170,7 @@ CONFIG_ARCH_SHMOBILE=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -176,8 +180,6 @@ CONFIG_ARCH_SHMOBILE=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 CONFIG_CPU_SUBTYPE_SH7366=y
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -584,6 +586,7 @@ CONFIG_SCSI_WAIT_SCAN=m
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
 # CONFIG_SCSI_OSD_INITIATOR is not set
@@ -936,6 +939,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -957,6 +961,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1005,6 +1014,7 @@ CONFIG_CRAMFS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
@@ -1095,10 +1105,24 @@ CONFIG_FRAME_WARN=1024
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -1208,6 +1232,7 @@ CONFIG_CRYPTO_ARC4=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index d174b1a4d802a8e003b3dd420d6d02c7c53132a0..512664fed66c0dabd7aeb7484f3c0badc9a33aa1 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29
-# Thu Apr  2 19:33:39 2009
+# Linux kernel version: 2.6.30-rc3
+# Mon Apr 27 14:02:55 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
 CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_BUG=y
@@ -76,6 +77,7 @@ CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -94,6 +96,7 @@ CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 CONFIG_PROFILING=y
+# CONFIG_MARKERS is not set
 # CONFIG_OPROFILE is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
@@ -102,6 +105,8 @@ CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -114,7 +119,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL 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
 
@@ -162,6 +166,7 @@ CONFIG_CPU_SHX3=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
 # CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7724 is not set
 # CONFIG_CPU_SUBTYPE_SH7763 is not set
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
@@ -171,8 +176,6 @@ CONFIG_CPU_SUBTYPE_SH7786=y
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 # CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
 
 #
 # Memory management options
@@ -900,15 +903,17 @@ CONFIG_USB_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
+# CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
+# CONFIG_HID_KYE is not set
 CONFIG_HID_GYRATION=y
+# CONFIG_HID_KENSINGTON is not set
 CONFIG_HID_LOGITECH=y
 # CONFIG_LOGITECH_FF is not set
 # CONFIG_LOGIRUMBLEPAD2_FF is not set
@@ -1046,6 +1051,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -1067,6 +1073,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1117,6 +1128,7 @@ CONFIG_MINIX_FS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -1209,10 +1221,24 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
 #
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_SH_STANDARD_BIOS is not set
@@ -1322,6 +1348,7 @@ CONFIG_CRYPTO_DES=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index 666713ac5fcff14b8f0ba667dba73482e282825a..63e9dd30b41c08df0e57a1b078255f81210d221b 100644 (file)
@@ -16,7 +16,8 @@ config SH_DMA_IRQ_MULTI
                     CPU_SUBTYPE_SH7750S || CPU_SUBTYPE_SH7750R || \
                     CPU_SUBTYPE_SH7751R || CPU_SUBTYPE_SH7091  || \
                     CPU_SUBTYPE_SH7763  || CPU_SUBTYPE_SH7764  || \
-                    CPU_SUBTYPE_SH7780  || CPU_SUBTYPE_SH7785
+                    CPU_SUBTYPE_SH7780  || CPU_SUBTYPE_SH7785  || \
+                    CPU_SUBTYPE_SH7760
 
 config NR_ONCHIP_DMA_CHANNELS
        int
index 7e816ededed762db82b04ce39b7bc2b449e9f769..e8db585a6638a6617285044cef4e0b7293d2c31e 100644 (file)
@@ -17,21 +17,3 @@ config SH_PCIDMA_NONCOHERENT
          code will not have to flush the CPU's caches. If you have a PCI host
          bridge integrated with your SH CPU, refer carefully to the chip specs
          to see if you can say 'N' here. Otherwise, leave it as 'Y'.
-
-# This is also board-specific
-config PCI_AUTO
-       bool
-       depends on PCI
-       default y
-
-config PCI_AUTO_UPDATE_RESOURCES
-       bool
-       depends on PCI_AUTO
-       default y if !SH_DREAMCAST
-       help
-         Selecting this option will cause the PCI auto code to leave your
-         BAR values alone. Otherwise they will be updated automatically. If
-         for some reason, you have a board that simply refuses to work
-         with its resources updated beyond what they are when the device
-         is powered up, set this to N. Everyone else will want this as Y.
-
index 847e90894d1b45e8d43a04696c3310f7e9a7242d..d2ffc477549ad6fe0897ad11df6ad015cbdf4a8e 100644 (file)
@@ -1,9 +1,7 @@
 #
 # Makefile for the PCI specific kernel interface routines under Linux.
 #
-
 obj-y                                  += pci.o
-obj-$(CONFIG_PCI_AUTO)                 += pci-auto.o
 
 obj-$(CONFIG_CPU_SUBTYPE_SH7751)       += pci-sh7751.o ops-sh4.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7751R)      += pci-sh7751.o ops-sh4.o
@@ -12,15 +10,17 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7780)    += pci-sh7780.o ops-sh4.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7785)       += pci-sh7780.o ops-sh4.o
 obj-$(CONFIG_CPU_SH5)                  += pci-sh5.o ops-sh5.o
 
-obj-$(CONFIG_SH_DREAMCAST)             += ops-dreamcast.o fixups-dreamcast.o
-obj-$(CONFIG_SH_SECUREEDGE5410)                += ops-snapgear.o
-obj-$(CONFIG_SH_RTS7751R2D)            += ops-rts7751r2d.o fixups-rts7751r2d.o
-obj-$(CONFIG_SH_SH03)                  += ops-sh03.o fixups-sh03.o
-obj-$(CONFIG_SH_HIGHLANDER)            += ops-r7780rp.o fixups-r7780rp.o
-obj-$(CONFIG_SH_SDK7780)               += ops-sdk7780.o fixups-sdk7780.o
-obj-$(CONFIG_SH_TITAN)                 += ops-titan.o
-obj-$(CONFIG_SH_LANDISK)               += ops-landisk.o
-obj-$(CONFIG_SH_LBOX_RE2)              += ops-lboxre2.o fixups-lboxre2.o
-obj-$(CONFIG_SH_7780_SOLUTION_ENGINE)  += ops-se7780.o fixups-se7780.o
-obj-$(CONFIG_SH_CAYMAN)                        += ops-cayman.o
-obj-$(CONFIG_SH_SH7785LCR)             += ops-sh7785lcr.o fixups-sh7785lcr.o
+obj-$(CONFIG_SH_DREAMCAST)             += ops-dreamcast.o fixups-dreamcast.o \
+                                          pci-dreamcast.o
+obj-$(CONFIG_SH_SECUREEDGE5410)                += fixups-snapgear.o
+obj-$(CONFIG_SH_7751_SOLUTION_ENGINE)  += fixups-se7751.o
+obj-$(CONFIG_SH_RTS7751R2D)            += fixups-rts7751r2d.o
+obj-$(CONFIG_SH_SH03)                  += fixups-sh03.o
+obj-$(CONFIG_SH_HIGHLANDER)            += fixups-r7780rp.o
+obj-$(CONFIG_SH_SH7785LCR)             += fixups-r7780rp.o
+obj-$(CONFIG_SH_SDK7780)               += fixups-sdk7780.o
+obj-$(CONFIG_SH_7780_SOLUTION_ENGINE)  += fixups-sdk7780.o
+obj-$(CONFIG_SH_TITAN)                 += fixups-titan.o
+obj-$(CONFIG_SH_LANDISK)               += fixups-landisk.o
+obj-$(CONFIG_SH_LBOX_RE2)              += fixups-rts7751r2d.o
+obj-$(CONFIG_SH_CAYMAN)                        += fixups-cayman.o
similarity index 88%
rename from arch/sh/drivers/pci/ops-cayman.c
rename to arch/sh/drivers/pci/fixups-cayman.c
index 38ef76207af6c8ecaf43c53ccc0d98013396ad9d..b68b61d22c6cd4aab727f2754fbe20617c872c1c 100644 (file)
@@ -75,15 +75,3 @@ int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
 
        return result;
 }
-
-struct pci_channel board_pci_channels[] = {
-       { &sh5_pci_ops, NULL, NULL, 0, 0xff },
-       { NULL, NULL, NULL, 0, 0 },
-};
-EXPORT_SYMBOL(board_pci_channels);
-
-int __init pcibios_init_platform(void)
-{
-       return sh5pci_init(__pa(memory_start),
-                          __pa(memory_end) - __pa(memory_start));
-}
index 2bf85cf091e13bda25657f76bd1d9c4952ebeedc..ed7f489936f1e3075428434ef61b8f0739150084 100644 (file)
@@ -30,7 +30,7 @@
 
 static void __init gapspci_fixup_resources(struct pci_dev *dev)
 {
-       struct pci_channel *p = board_pci_channels;
+       struct pci_channel *p = dev->sysdata;
 
        printk(KERN_NOTICE "PCI: Fixing up device %s\n", pci_name(dev));
 
@@ -41,6 +41,13 @@ static void __init gapspci_fixup_resources(struct pci_dev *dev)
                 */
                dev->resource[1].start  = p->io_resource->start  + 0x100;
                dev->resource[1].end    = dev->resource[1].start + 0x200 - 1;
+
+               /*
+                * This is not a normal BAR, prevent any attempts to move
+                * the BAR, as this will result in a bus lock.
+                */
+               dev->resource[1].flags |= IORESOURCE_PCI_FIXED;
+
                /*
                 * Redirect dma memory allocations to special memory window.
                 */
similarity index 51%
rename from arch/sh/drivers/pci/ops-landisk.c
rename to arch/sh/drivers/pci/fixups-landisk.c
index bff09ecf34198a1d5f91e3233038d06b2b4323cb..bb1a6bb5149edac820e6714256e94acae4001085 100644 (file)
 #include <linux/pci.h>
 #include "pci-sh4.h"
 
-static struct resource sh7751_io_resource = {
-       .name = "SH7751 IO",
-       .start = SH7751_PCI_IO_BASE,
-       .end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
-       .flags = IORESOURCE_IO
-};
-
-static struct resource sh7751_mem_resource = {
-       .name = "SH7751 mem",
-       .start = SH7751_PCI_MEMORY_BASE,
-       .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
-       .flags = IORESOURCE_MEM
-};
-
-struct pci_channel board_pci_channels[] = {
-       {&sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0x3ff},
-       {NULL, NULL, NULL, 0, 0},
-};
-
-static struct sh4_pci_address_map sh7751_pci_map = {
-       .window0 = {
-               .base   = SH7751_CS3_BASE_ADDR,
-               .size   = (64 << 20),   /* 64MB */
-       },
-
-       .flags = SH4_PCIC_NO_RESET,
-};
-
-int __init pcibios_init_platform(void)
-{
-       return sh7751_pcic_init(&sh7751_pci_map);
-}
-
 int pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
 {
        /*
diff --git a/arch/sh/drivers/pci/fixups-lboxre2.c b/arch/sh/drivers/pci/fixups-lboxre2.c
deleted file mode 100644 (file)
index 1c1d412..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * arch/sh/drivers/pci/fixups-lboxre2.c
- *
- * L-BOX RE2 PCI fixups
- *
- * Copyright (C) 2007 Nobuhiro Iwamatsu
- *
- * 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.
- */
-#include "pci-sh4.h"
-
-#define PCIMCR_MRSET_OFF       0xBFFFFFFF
-#define PCIMCR_RFSH_OFF                0xFFFFFFFB
-
-int pci_fixup_pcic(void)
-{
-       unsigned long bcr1, mcr;
-
-       bcr1 = ctrl_inl(SH7751_BCR1);
-       bcr1 |= 0x40080000;     /* Enable Bit 19 BREQEN, set PCIC to slave */
-       pci_write_reg(bcr1, SH4_PCIBCR1);
-
-       /* Enable all interrupts, so we known what to fix */
-       pci_write_reg(0x0000c3ff, SH4_PCIINTM);
-       pci_write_reg(0x0000380f, SH4_PCIAINTM);
-       pci_write_reg(0xfb900047, SH7751_PCICONF1);
-       pci_write_reg(0xab000001, SH7751_PCICONF4);
-
-       mcr = ctrl_inl(SH7751_MCR);
-       mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
-       pci_write_reg(mcr, SH4_PCIMCR);
-
-       pci_write_reg(0x0c000000, SH7751_PCICONF5);
-       pci_write_reg(0xd0000000, SH7751_PCICONF6);
-       pci_write_reg(0x0c000000, SH4_PCILAR0);
-       pci_write_reg(0x00000000, SH4_PCILAR1);
-
-       return 0;
-}
index 3e321df65d22a9a7723f630496405bdca854e17b..15ca65cb667e780afc576ef69158161b53b0c362 100644 (file)
  * for more details.
  */
 #include <linux/pci.h>
+#include <linux/io.h>
 #include "pci-sh4.h"
-#include <asm/io.h>
 
-int pci_fixup_pcic(void)
-{
-       pci_write_reg(0x000043ff, SH4_PCIINTM);
-       pci_write_reg(0x0000380f, SH4_PCIAINTM);
-
-       pci_write_reg(0xfbb00047, SH7780_PCICMD);
-       pci_write_reg(0x00000000, SH7780_PCIIBAR);
-
-       pci_write_reg(0x00011912, SH7780_PCISVID);
-       pci_write_reg(0x08000000, SH7780_PCICSCR0);
-       pci_write_reg(0x0000001b, SH7780_PCICSAR0);
-       pci_write_reg(0xfd000000, SH7780_PCICSCR1);
-       pci_write_reg(0x0000000f, SH7780_PCICSAR1);
-
-       pci_write_reg(0xfd000000, SH7780_PCIMBR0);
-       pci_write_reg(0x00fc0000, SH7780_PCIMBMR0);
+static char irq_tab[] __initdata = {
+       65, 66, 67, 68,
+};
 
-#ifdef CONFIG_32BIT
-       pci_write_reg(0xc0000000, SH7780_PCIMBR2);
-       pci_write_reg(0x20000000 - SH7780_PCI_IO_SIZE, SH7780_PCIMBMR2);
-#endif
+int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+{
+       return irq_tab[slot];
+}
 
-       /* Set IOBR for windows containing area specified in pci.h */
-       pci_write_reg((PCIBIOS_MIN_IO & ~(SH7780_PCI_IO_SIZE - 1)),
-                     SH7780_PCIIOBR);
-       pci_write_reg(((SH7780_PCI_IO_SIZE-1) & (7<<18)), SH7780_PCIIOBMR);
+int pci_fixup_pcic(struct pci_channel *chan)
+{
+       pci_write_reg(chan, 0x000043ff, SH4_PCIINTM);
+       pci_write_reg(chan, 0x00000000, SH7780_PCIIBAR);
+       pci_write_reg(chan, 0x08000000, SH7780_PCICSCR0);
+       pci_write_reg(chan, 0x0000001b, SH7780_PCICSAR0);
+       pci_write_reg(chan, 0xfd000000, SH7780_PCICSCR1);
+       pci_write_reg(chan, 0x0000000f, SH7780_PCICSAR1);
 
        return 0;
 }
index 904bce8768d3b2360899cfdf97c00d44b11b4beb..052b354236dcf02e039d539254c3a5e66e00e0de 100644 (file)
@@ -1,43 +1,67 @@
 /*
  * arch/sh/drivers/pci/fixups-rts7751r2d.c
  *
- * RTS7751R2D PCI fixups
+ * RTS7751R2D / LBOXRE2 PCI fixups
  *
  * Copyright (C) 2003  Lineo uSolutions, Inc.
  * Copyright (C) 2004  Paul Mundt
+ * Copyright (C) 2007  Nobuhiro Iwamatsu
  *
  * 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.
  */
+#include <linux/pci.h>
+#include <mach/lboxre2.h>
+#include <mach/r2d.h>
 #include "pci-sh4.h"
+#include <asm/machtypes.h>
 
 #define PCIMCR_MRSET_OFF       0xBFFFFFFF
 #define PCIMCR_RFSH_OFF                0xFFFFFFFB
 
-int pci_fixup_pcic(void)
+static u8 rts7751r2d_irq_tab[] __initdata = {
+       IRQ_PCI_INTA,
+       IRQ_PCI_INTB,
+       IRQ_PCI_INTC,
+       IRQ_PCI_INTD,
+};
+
+static char lboxre2_irq_tab[] __initdata = {
+       IRQ_ETH0, IRQ_ETH1, IRQ_INTA, IRQ_INTD,
+};
+
+int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+{
+       if (mach_is_lboxre2())
+               return lboxre2_irq_tab[slot];
+       else
+               return rts7751r2d_irq_tab[slot];
+}
+
+int pci_fixup_pcic(struct pci_channel *chan)
 {
        unsigned long bcr1, mcr;
 
        bcr1 = ctrl_inl(SH7751_BCR1);
        bcr1 |= 0x40080000;     /* Enable Bit 19 BREQEN, set PCIC to slave */
-       pci_write_reg(bcr1, SH4_PCIBCR1);
+       pci_write_reg(chan, bcr1, SH4_PCIBCR1);
 
        /* Enable all interrupts, so we known what to fix */
-       pci_write_reg(0x0000c3ff, SH4_PCIINTM);
-       pci_write_reg(0x0000380f, SH4_PCIAINTM);
+       pci_write_reg(chan, 0x0000c3ff, SH4_PCIINTM);
+       pci_write_reg(chan, 0x0000380f, SH4_PCIAINTM);
 
-       pci_write_reg(0xfb900047, SH7751_PCICONF1);
-       pci_write_reg(0xab000001, SH7751_PCICONF4);
+       pci_write_reg(chan, 0xfb900047, SH7751_PCICONF1);
+       pci_write_reg(chan, 0xab000001, SH7751_PCICONF4);
 
        mcr = ctrl_inl(SH7751_MCR);
        mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
-       pci_write_reg(mcr, SH4_PCIMCR);
+       pci_write_reg(chan, mcr, SH4_PCIMCR);
 
-       pci_write_reg(0x0c000000, SH7751_PCICONF5);
-       pci_write_reg(0xd0000000, SH7751_PCICONF6);
-       pci_write_reg(0x0c000000, SH4_PCILAR0);
-       pci_write_reg(0x00000000, SH4_PCILAR1);
+       pci_write_reg(chan, 0x0c000000, SH7751_PCICONF5);
+       pci_write_reg(chan, 0xd0000000, SH7751_PCICONF6);
+       pci_write_reg(chan, 0x0c000000, SH4_PCILAR0);
+       pci_write_reg(chan, 0x00000000, SH4_PCILAR1);
 
        return 0;
 }
index 2f8863099dd1572bed0d4ed0d7ab764d226fe8b9..250b0edd736538b3e92bda9ee29cda962b931a28 100644 (file)
@@ -5,55 +5,48 @@
  *
  * Copyright (C) 2003  Lineo uSolutions, Inc.
  * Copyright (C) 2004 - 2006  Paul Mundt
+ * Copyright (C) 2006  Nobuhiro Iwamatsu
  *
  * 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.
  */
 #include <linux/pci.h>
+#include <linux/io.h>
 #include "pci-sh4.h"
-#include <asm/io.h>
 
-int pci_fixup_pcic(void)
+/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */
+static char sdk7780_irq_tab[4][16] __initdata = {
+       /* INTA */
+       { 65, 68, 67, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+       /* INTB */
+       { 66, 65, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+       /* INTC */
+       { 67, 66, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+       /* INTD */
+       { 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+};
+
+int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+{
+       return sdk7780_irq_tab[pin-1][slot];
+}
+int pci_fixup_pcic(struct pci_channel *chan)
 {
-       ctrl_outl(0x00000001, SH7780_PCI_VCR2);
-
        /* Enable all interrupts, so we know what to fix */
-       pci_write_reg(0x0000C3FF, SH7780_PCIIMR);
-       pci_write_reg(0x0000380F, SH7780_PCIAINTM);
+       pci_write_reg(chan, 0x0000C3FF, SH7780_PCIIMR);
 
        /* Set up standard PCI config registers */
-       pci_write_reg(0xFB00, SH7780_PCISTATUS);
-       pci_write_reg(0x0047, SH7780_PCICMD);
-       pci_write_reg(0x00, SH7780_PCIPIF);
-       pci_write_reg(0x00, SH7780_PCISUB);
-       pci_write_reg(0x06, SH7780_PCIBCC);
-       pci_write_reg(0x1912, SH7780_PCISVID);
-       pci_write_reg(0x0001, SH7780_PCISID);
-
-       pci_write_reg(0x08000000, SH7780_PCIMBAR0);     /* PCI */
-       pci_write_reg(0x08000000, SH7780_PCILAR0);      /* SHwy */
-       pci_write_reg(0x07F00001, SH7780_PCILSR);       /* size 128M w/ MBAR */
-
-       pci_write_reg(0x00000000, SH7780_PCIMBAR1);
-       pci_write_reg(0x00000000, SH7780_PCILAR1);
-       pci_write_reg(0x00000000, SH7780_PCILSR1);
-
-       pci_write_reg(0xAB000801, SH7780_PCIIBAR);
-
-       /*
-        * Set the MBR so PCI address is one-to-one with window,
-        * meaning all calls go straight through... use ifdef to
-        * catch erroneous assumption.
-        */
-       pci_write_reg(0xFD000000 , SH7780_PCIMBR0);
-       pci_write_reg(0x00FC0000 , SH7780_PCIMBMR0);    /* 16M */
+       pci_write_reg(chan, 0x08000000, SH7780_PCIMBAR0);       /* PCI */
+       pci_write_reg(chan, 0x08000000, SH4_PCILAR0);   /* SHwy */
+       pci_write_reg(chan, 0x07F00001, SH4_PCILSR0);   /* size 128M w/ MBAR */
 
-       /* Set IOBR for window containing area specified in pci.h */
-       pci_write_reg(PCIBIOS_MIN_IO & ~(SH7780_PCI_IO_SIZE-1), SH7780_PCIIOBR);
-       pci_write_reg((SH7780_PCI_IO_SIZE-1) & (7 << 18), SH7780_PCIIOBMR);
+       pci_write_reg(chan, 0x00000000, SH7780_PCIMBAR1);
+       pci_write_reg(chan, 0x00000000, SH4_PCILAR1);
+       pci_write_reg(chan, 0x00000000, SH4_PCILSR1);
 
-       pci_write_reg(0xA5000C01, SH7780_PCICR);
+       pci_write_reg(chan, 0xAB000801, SH7780_PCIIBAR);
+       pci_write_reg(chan, 0xA5000C01, SH4_PCICR);
 
        return 0;
 }
diff --git a/arch/sh/drivers/pci/fixups-se7751.c b/arch/sh/drivers/pci/fixups-se7751.c
new file mode 100644 (file)
index 0000000..475fa9f
--- /dev/null
@@ -0,0 +1,111 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include "pci-sh4.h"
+
+int __init pcibios_map_platform_irq(u8 slot, u8 pin)
+{
+        switch (slot) {
+        case 0: return 13;
+        case 1: return 13;     /* AMD Ethernet controller */
+        case 2: return -1;
+        case 3: return -1;
+        case 4: return -1;
+        default:
+                printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
+                return -1;
+        }
+}
+
+#define PCIMCR_MRSET_OFF       0xBFFFFFFF
+#define PCIMCR_RFSH_OFF                0xFFFFFFFB
+
+/*
+ * Only long word accesses of the PCIC's internal local registers and the
+ * configuration registers from the CPU is supported.
+ */
+#define PCIC_WRITE(x,v) writel((v), PCI_REG(x))
+#define PCIC_READ(x) readl(PCI_REG(x))
+
+/*
+ * Description:  This function sets up and initializes the pcic, sets
+ * up the BARS, maps the DRAM into the address space etc, etc.
+ */
+int pci_fixup_pcic(struct pci_channel *chan)
+{
+       unsigned long bcr1, wcr1, wcr2, wcr3, mcr;
+       unsigned short bcr2;
+
+       /*
+       * Initialize the slave bus controller on the pcic.  The values used
+       * here should not be hardcoded, but they should be taken from the bsc
+       * on the processor, to make this function as generic as possible.
+       * (i.e. Another sbc may usr different SDRAM timing settings -- in order
+       * for the pcic to work, its settings need to be exactly the same.)
+       */
+       bcr1 = (*(volatile unsigned long*)(SH7751_BCR1));
+       bcr2 = (*(volatile unsigned short*)(SH7751_BCR2));
+       wcr1 = (*(volatile unsigned long*)(SH7751_WCR1));
+       wcr2 = (*(volatile unsigned long*)(SH7751_WCR2));
+       wcr3 = (*(volatile unsigned long*)(SH7751_WCR3));
+       mcr = (*(volatile unsigned long*)(SH7751_MCR));
+
+       bcr1 = bcr1 | 0x00080000;  /* Enable Bit 19, BREQEN */
+       (*(volatile unsigned long*)(SH7751_BCR1)) = bcr1;
+
+       bcr1 = bcr1 | 0x40080000;  /* Enable Bit 19 BREQEN, set PCIC to slave */
+       PCIC_WRITE(SH7751_PCIBCR1, bcr1);        /* PCIC BCR1 */
+       PCIC_WRITE(SH7751_PCIBCR2, bcr2);     /* PCIC BCR2 */
+       PCIC_WRITE(SH7751_PCIWCR1, wcr1);     /* PCIC WCR1 */
+       PCIC_WRITE(SH7751_PCIWCR2, wcr2);     /* PCIC WCR2 */
+       PCIC_WRITE(SH7751_PCIWCR3, wcr3);     /* PCIC WCR3 */
+       mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
+       PCIC_WRITE(SH7751_PCIMCR, mcr);      /* PCIC MCR */
+
+
+       /* Enable all interrupts, so we know what to fix */
+       PCIC_WRITE(SH7751_PCIINTM, 0x0000c3ff);
+       PCIC_WRITE(SH7751_PCIAINTM, 0x0000380f);
+
+       /* Set up standard PCI config registers */
+       PCIC_WRITE(SH7751_PCICONF1,     0xF39000C7); /* Bus Master, Mem & I/O access */
+       PCIC_WRITE(SH7751_PCICONF2,     0x00000000); /* PCI Class code & Revision ID */
+       PCIC_WRITE(SH7751_PCICONF4,     0xab000001); /* PCI I/O address (local regs) */
+       PCIC_WRITE(SH7751_PCICONF5,     0x0c000000); /* PCI MEM address (local RAM)  */
+       PCIC_WRITE(SH7751_PCICONF6,     0xd0000000); /* PCI MEM address (unused)     */
+       PCIC_WRITE(SH7751_PCICONF11, 0x35051054); /* PCI Subsystem ID & Vendor ID */
+       PCIC_WRITE(SH7751_PCILSR0, 0x03f00000);   /* MEM (full 64M exposed)       */
+       PCIC_WRITE(SH7751_PCILSR1, 0x00000000);   /* MEM (unused)                 */
+       PCIC_WRITE(SH7751_PCILAR0, 0x0c000000);   /* MEM (direct map from PCI)    */
+       PCIC_WRITE(SH7751_PCILAR1, 0x00000000);   /* MEM (unused)                 */
+
+       /* Now turn it on... */
+       PCIC_WRITE(SH7751_PCICR, 0xa5000001);
+
+       /*
+       * Set PCIMBR and PCIIOBR here, assuming a single window
+       * (16M MEM, 256K IO) is enough.  If a larger space is
+       * needed, the readx/writex and inx/outx functions will
+       * have to do more (e.g. setting registers for each call).
+       */
+
+       /*
+       * Set the MBR so PCI address is one-to-one with window,
+       * meaning all calls go straight through... use BUG_ON to
+       * catch erroneous assumption.
+       */
+       BUG_ON(chan->mem_resource->start != SH7751_PCI_MEMORY_BASE);
+
+       PCIC_WRITE(SH7751_PCIMBR, chan->mem_resource->start);
+
+       /* Set IOBR for window containing area specified in pci.h */
+       PCIC_WRITE(SH7751_PCIIOBR, (chan->io_resource->start & SH7751_PCIIOBR_MASK));
+
+       /* All done, may as well say so... */
+       printk("SH7751 PCI: Finished initialization of the PCI controller\n");
+
+       return 1;
+}
diff --git a/arch/sh/drivers/pci/fixups-se7780.c b/arch/sh/drivers/pci/fixups-se7780.c
deleted file mode 100644 (file)
index 880cea1..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * arch/sh/drivers/pci/fixups-se7780.c
- *
- * HITACHI UL Solution Engine 7780  PCI fixups
- *
- * Copyright (C) 2003  Lineo uSolutions, Inc.
- * Copyright (C) 2004 - 2006  Paul Mundt
- * Copyright (C) 2006  Nobuhiro Iwamatsu
- *
- * 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.
- */
-#include <linux/pci.h>
-#include "pci-sh4.h"
-#include <asm/io.h>
-
-int pci_fixup_pcic(void)
-{
-       ctrl_outl(0x00000001, SH7780_PCI_VCR2);
-
-       /* Enable all interrupts, so we know what to fix */
-       pci_write_reg(0x0000C3FF, SH7780_PCIIMR);
-       pci_write_reg(0x0000380F, SH7780_PCIAINTM);
-
-       /* Set up standard PCI config registers */
-       ctrl_outw(0xFB00, PCI_REG(SH7780_PCISTATUS));
-       ctrl_outw(0x0047, PCI_REG(SH7780_PCICMD));
-       ctrl_outb(  0x00, PCI_REG(SH7780_PCIPIF));
-       ctrl_outb(  0x00, PCI_REG(SH7780_PCISUB));
-       ctrl_outb(  0x06, PCI_REG(SH7780_PCIBCC));
-       ctrl_outw(0x1912, PCI_REG(SH7780_PCISVID));
-       ctrl_outw(0x0001, PCI_REG(SH7780_PCISID));
-
-       pci_write_reg(0x08000000, SH7780_PCIMBAR0);     /* PCI */
-       pci_write_reg(0x08000000, SH7780_PCILAR0);     /* SHwy */
-       pci_write_reg(0x07F00001, SH7780_PCILSR);      /* size 128M w/ MBAR */
-
-       pci_write_reg(0x00000000, SH7780_PCIMBAR1);
-       pci_write_reg(0x00000000, SH7780_PCILAR1);
-       pci_write_reg(0x00000000, SH7780_PCILSR1);
-
-       pci_write_reg(0xAB000801, SH7780_PCIIBAR);
-
-       /*
-        * Set the MBR so PCI address is one-to-one with window,
-        * meaning all calls go straight through... use ifdef to
-        * catch erroneous assumption.
-        */
-       pci_write_reg(0xFD000000 , SH7780_PCIMBR0);
-       pci_write_reg(0x00FC0000 , SH7780_PCIMBMR0);    /* 16M */
-
-       /* Set IOBR for window containing area specified in pci.h */
-       pci_write_reg(PCIBIOS_MIN_IO & ~(SH7780_PCI_IO_SIZE-1), SH7780_PCIIOBR);
-       pci_write_reg((SH7780_PCI_IO_SIZE-1) & (7 << 18), SH7780_PCIIOBMR);
-
-       pci_write_reg(0xA5000C01, SH7780_PCICR);
-
-       return 0;
-}
diff --git a/arch/sh/drivers/pci/fixups-sh7785lcr.c b/arch/sh/drivers/pci/fixups-sh7785lcr.c
deleted file mode 100644 (file)
index 4949e60..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * arch/sh/drivers/pci/fixups-sh7785lcr.c
- *
- * R0P7785LC0011RL PCI fixups
- * Copyright (C) 2008  Yoshihiro Shimoda
- *
- * Based on arch/sh/drivers/pci/fixups-r7780rp.c
- * Copyright (C) 2003  Lineo uSolutions, Inc.
- * Copyright (C) 2004 - 2006  Paul Mundt
- *
- * 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.
- */
-#include <linux/pci.h>
-#include "pci-sh4.h"
-
-int pci_fixup_pcic(void)
-{
-       pci_write_reg(0x000043ff, SH4_PCIINTM);
-       pci_write_reg(0x0000380f, SH4_PCIAINTM);
-
-       pci_write_reg(0xfbb00047, SH7780_PCICMD);
-       pci_write_reg(0x00000000, SH7780_PCIIBAR);
-
-       pci_write_reg(0x00011912, SH7780_PCISVID);
-       pci_write_reg(0x08000000, SH7780_PCICSCR0);
-       pci_write_reg(0x0000001b, SH7780_PCICSAR0);
-       pci_write_reg(0xfd000000, SH7780_PCICSCR1);
-       pci_write_reg(0x0000000f, SH7780_PCICSAR1);
-
-       pci_write_reg(0xfd000000, SH7780_PCIMBR0);
-       pci_write_reg(0x00fc0000, SH7780_PCIMBMR0);
-
-#ifdef CONFIG_32BIT
-       pci_write_reg(0xc0000000, SH7780_PCIMBR2);
-       pci_write_reg(0x20000000 - SH7780_PCI_IO_SIZE, SH7780_PCIMBMR2);
-#endif
-
-       /* Set IOBR for windows containing area specified in pci.h */
-       pci_write_reg((PCIBIOS_MIN_IO & ~(SH7780_PCI_IO_SIZE - 1)),
-                     SH7780_PCIIOBR);
-       pci_write_reg(((SH7780_PCI_IO_SIZE - 1) & (7 << 18)), SH7780_PCIIOBMR);
-
-       return 0;
-}
diff --git a/arch/sh/drivers/pci/fixups-snapgear.c b/arch/sh/drivers/pci/fixups-snapgear.c
new file mode 100644 (file)
index 0000000..5a39ecc
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * arch/sh/drivers/pci/ops-snapgear.c
+ *
+ * Author:  David McCullough <davidm@snapgear.com>
+ *
+ * Ported to new API by Paul Mundt <lethal@linux-sh.org>
+ *
+ * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * PCI initialization for the SnapGear boards
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include "pci-sh4.h"
+
+int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+{
+       int irq = -1;
+
+       switch (slot) {
+       case 8:  /* the PCI bridge */ break;
+       case 11: irq = 8;  break; /* USB    */
+       case 12: irq = 11; break; /* PCMCIA */
+       case 13: irq = 5;  break; /* eth0   */
+       case 14: irq = 8;  break; /* eth1   */
+       case 15: irq = 11; break; /* safenet (unused) */
+       }
+
+       printk("PCI: Mapping SnapGear IRQ for slot %d, pin %c to irq %d\n",
+              slot, pin - 1 + 'A', irq);
+
+       return irq;
+}
similarity index 50%
rename from arch/sh/drivers/pci/ops-titan.c
rename to arch/sh/drivers/pci/fixups-titan.c
index a8f7801a34afb038451daf47e2c5cc717aa592d6..3a79fa8254a6317a0b0c3020ecd3fdd2ac39f28c 100644 (file)
@@ -36,42 +36,3 @@ int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
 
        return irq;
 }
-
-static struct resource sh7751_io_resource = {
-       .name   = "SH7751_IO",
-       .start  = SH7751_PCI_IO_BASE,
-       .end    = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
-       .flags  = IORESOURCE_IO
-};
-
-static struct resource sh7751_mem_resource = {
-       .name   = "SH7751_mem",
-       .start  = SH7751_PCI_MEMORY_BASE,
-       .end    = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
-       .flags  = IORESOURCE_MEM
-};
-
-struct pci_channel board_pci_channels[] = {
-       { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
-       { NULL, NULL, NULL, 0, 0 },
-};
-EXPORT_SYMBOL(board_pci_channels);
-
-static struct sh4_pci_address_map sh7751_pci_map = {
-       .window0        = {
-               .base   = SH7751_CS2_BASE_ADDR,
-               .size   = SH7751_MEM_REGION_SIZE*2,     /* cs2 and cs3 */
-       },
-
-       .window1        = {
-               .base   = SH7751_CS2_BASE_ADDR,
-               .size   = SH7751_MEM_REGION_SIZE*2,
-       },
-
-       .flags  = SH4_PCIC_NO_RESET,
-};
-
-int __init pcibios_init_platform(void)
-{
-       return sh7751_pcic_init(&sh7751_pci_map);
-}
index f5d2a2aa6f3f88b00ecb46700d245b98b182390f..e83d0d3aabe25b66d524f139dda49427a8974c9d 100644 (file)
@@ -1,15 +1,9 @@
 /*
- * arch/sh/drivers/pci/ops-dreamcast.c
- *
  * PCI operations for the Sega Dreamcast
  *
  * Copyright (C) 2001, 2002  M. R. Brown
  * Copyright (C) 2002, 2003  Paul Mundt
  *
- * This file originally bore the message (with enclosed-$):
- *     Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp
- *     Dreamcast PCI: Supports SEGA Broadband Adaptor only.
- *
  * 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.
 #include <linux/irq.h>
 #include <linux/pci.h>
 #include <linux/module.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/irq.h>
 #include <mach/pci.h>
 
-static struct resource gapspci_io_resource = {
-       .name   = "GAPSPCI IO",
-       .start  = GAPSPCI_BBA_CONFIG,
-       .end    = GAPSPCI_BBA_CONFIG + GAPSPCI_BBA_CONFIG_SIZE - 1,
-       .flags  = IORESOURCE_IO,
-};
-
-static struct resource gapspci_mem_resource = {
-       .name   = "GAPSPCI mem",
-       .start  = GAPSPCI_DMA_BASE,
-       .end    = GAPSPCI_DMA_BASE + GAPSPCI_DMA_SIZE - 1,
-       .flags  = IORESOURCE_MEM,
-};
-
-static struct pci_ops gapspci_pci_ops;
-
-struct pci_channel board_pci_channels[] = {
-       { &gapspci_pci_ops, &gapspci_io_resource,
-         &gapspci_mem_resource, 0, 1 },
-       { 0, }
-};
-EXPORT_SYMBOL(board_pci_channels);
-
 /*
  * The !gapspci_config_access case really shouldn't happen, ever, unless
  * someone implicitly messes around with the last devfn value.. otherwise we
@@ -85,10 +55,10 @@ static int gapspci_read(struct pci_bus *bus, unsigned int devfn, int where, int
                return PCIBIOS_DEVICE_NOT_FOUND;
 
        switch (size) {
-               case 1: *val = inb(GAPSPCI_BBA_CONFIG+where); break;
-               case 2: *val = inw(GAPSPCI_BBA_CONFIG+where); break;
-               case 4: *val = inl(GAPSPCI_BBA_CONFIG+where); break;
-       }       
+       case 1: *val = inb(GAPSPCI_BBA_CONFIG+where); break;
+       case 2: *val = inw(GAPSPCI_BBA_CONFIG+where); break;
+       case 4: *val = inl(GAPSPCI_BBA_CONFIG+where); break;
+       }
 
         return PCIBIOS_SUCCESSFUL;
 }
@@ -99,72 +69,15 @@ static int gapspci_write(struct pci_bus *bus, unsigned int devfn, int where, int
                return PCIBIOS_DEVICE_NOT_FOUND;
 
        switch (size) {
-               case 1: outb(( u8)val, GAPSPCI_BBA_CONFIG+where); break;
-               case 2: outw((u16)val, GAPSPCI_BBA_CONFIG+where); break;
-               case 4: outl((u32)val, GAPSPCI_BBA_CONFIG+where); break;
+       case 1: outb(( u8)val, GAPSPCI_BBA_CONFIG+where); break;
+       case 2: outw((u16)val, GAPSPCI_BBA_CONFIG+where); break;
+       case 4: outl((u32)val, GAPSPCI_BBA_CONFIG+where); break;
        }
 
         return PCIBIOS_SUCCESSFUL;
 }
 
-static struct pci_ops gapspci_pci_ops = {
+struct pci_ops gapspci_pci_ops = {
        .read   = gapspci_read,
        .write  = gapspci_write,
 };
-
-/*
- * gapspci init
- */
-
-int __init gapspci_init(void)
-{
-       char idbuf[16];
-       int i;
-
-       /*
-        * FIXME: All of this wants documenting to some degree,
-        * even some basic register definitions would be nice.
-        *
-        * I haven't seen anything this ugly since.. maple.
-        */
-
-       for (i=0; i<16; i++)
-               idbuf[i] = inb(GAPSPCI_REGS+i);
-
-       if (strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16))
-               return -ENODEV;
-
-       outl(0x5a14a501, GAPSPCI_REGS+0x18);
-
-       for (i=0; i<1000000; i++)
-               ;
-
-       if (inl(GAPSPCI_REGS+0x18) != 1)
-               return -EINVAL;
-
-       outl(0x01000000, GAPSPCI_REGS+0x20);
-       outl(0x01000000, GAPSPCI_REGS+0x24);
-
-       outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28);
-       outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c);
-
-       outl(1, GAPSPCI_REGS+0x14);
-       outl(1, GAPSPCI_REGS+0x34);
-
-       /* Setting Broadband Adapter */
-       outw(0xf900, GAPSPCI_BBA_CONFIG+0x06);
-       outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30);
-       outb(0x00, GAPSPCI_BBA_CONFIG+0x3c);
-       outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d);
-       outw(0x0006, GAPSPCI_BBA_CONFIG+0x04);
-       outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10);
-       outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14);
-
-       return 0;
-}
-
-/* Haven't done anything here as yet */
-char * __devinit pcibios_setup(char *str)
-{
-       return str;
-}
diff --git a/arch/sh/drivers/pci/ops-lboxre2.c b/arch/sh/drivers/pci/ops-lboxre2.c
deleted file mode 100644 (file)
index 86c0b6f..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * linux/arch/sh/drivers/pci/ops-lboxre2.c
- *
- * Copyright (C) 2007 Nobuhiro Iwamatsu
- *
- * PCI initialization for the NTT COMWARE L-BOX RE2
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/io.h>
-#include <mach/lboxre2.h>
-#include "pci-sh4.h"
-
-static char lboxre2_irq_tab[] __initdata = {
-       IRQ_ETH0, IRQ_ETH1, IRQ_INTA, IRQ_INTD,
-};
-
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
-{
-       return lboxre2_irq_tab[slot];
-}
-
-static struct resource sh7751_io_resource = {
-       .name   = "SH7751_IO",
-       .start  = SH7751_PCI_IO_BASE ,
-       .end    = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
-       .flags  = IORESOURCE_IO
-};
-
-static struct resource sh7751_mem_resource = {
-       .name   = "SH7751_mem",
-       .start  = SH7751_PCI_MEMORY_BASE,
-       .end    = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
-       .flags  = IORESOURCE_MEM
-};
-
-extern struct pci_ops sh7751_pci_ops;
-
-struct pci_channel board_pci_channels[] = {
-       { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
-       { NULL, NULL, NULL, 0, 0 },
-};
-
-EXPORT_SYMBOL(board_pci_channels);
-
-static struct sh4_pci_address_map sh7751_pci_map = {
-       .window0        = {
-               .base   = SH7751_CS3_BASE_ADDR,
-               .size   = 0x04000000,
-       },
-       .window1        = {
-               .base   = 0x00000000,   /* Unused */
-               .size   = 0x00000000,   /* Unused */
-       },
-       .flags  = SH4_PCIC_NO_RESET,
-};
-
-int __init pcibios_init_platform(void)
-{
-       return sh7751_pcic_init(&sh7751_pci_map);
-}
diff --git a/arch/sh/drivers/pci/ops-r7780rp.c b/arch/sh/drivers/pci/ops-r7780rp.c
deleted file mode 100644 (file)
index 8555238..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Author:  Ian DaSilva (idasilva@mvista.com)
- *
- * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * PCI initialization for the Renesas SH7780 Highlander R7780RP-1 board
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <mach/highlander.h>
-#include <asm/io.h>
-#include "pci-sh4.h"
-
-static char irq_tab[] __initdata = {
-       65, 66, 67, 68,
-};
-
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
-{
-       return irq_tab[slot];
-}
-
-static struct resource sh7780_io_resource = {
-       .name   = "SH7780_IO",
-       .start  = SH7780_PCI_IO_BASE,
-       .end    = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1,
-       .flags  = IORESOURCE_IO
-};
-
-static struct resource sh7780_mem_resource = {
-       .name   = "SH7780_mem",
-       .start  = SH7780_PCI_MEMORY_BASE,
-       .end    = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
-       .flags  = IORESOURCE_MEM
-};
-
-extern struct pci_ops sh7780_pci_ops;
-
-struct pci_channel board_pci_channels[] = {
-       { &sh4_pci_ops, &sh7780_io_resource, &sh7780_mem_resource, 0, 0xff },
-       { NULL, NULL, NULL, 0, 0 },
-};
-EXPORT_SYMBOL(board_pci_channels);
-
-static struct sh4_pci_address_map sh7780_pci_map = {
-       .window0        = {
-               .base   = SH7780_CS2_BASE_ADDR,
-               .size   = 0x04000000,
-       },
-
-       .window1        = {
-               .base   = SH7780_CS3_BASE_ADDR,
-               .size   = 0x04000000,
-       },
-
-       .flags  = SH4_PCIC_NO_RESET,
-};
-
-int __init pcibios_init_platform(void)
-{
-       return sh7780_pcic_init(&sh7780_pci_map);
-}
diff --git a/arch/sh/drivers/pci/ops-rts7751r2d.c b/arch/sh/drivers/pci/ops-rts7751r2d.c
deleted file mode 100644 (file)
index d6ca74b..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * linux/arch/sh/drivers/pci/ops-rts7751r2d.c
- *
- * Author:  Ian DaSilva (idasilva@mvista.com)
- *
- * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * PCI initialization for the Renesas SH7751R RTS7751R2D board
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/io.h>
-#include <mach/r2d.h>
-#include "pci-sh4.h"
-
-static u8 rts7751r2d_irq_tab[] __initdata = {
-       IRQ_PCI_INTA,
-       IRQ_PCI_INTB,
-       IRQ_PCI_INTC,
-       IRQ_PCI_INTD,
-};
-
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
-{
-       return rts7751r2d_irq_tab[slot];
-}
-
-static struct resource sh7751_io_resource = {
-       .name   = "SH7751_IO",
-       .start  = 0x4000,
-       .end    = SH7751_PCI_IO_SIZE - 1,
-       .flags  = IORESOURCE_IO
-};
-
-static struct resource sh7751_mem_resource = {
-       .name   = "SH7751_mem",
-       .start  = SH7751_PCI_MEMORY_BASE,
-       .end    = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
-       .flags  = IORESOURCE_MEM
-};
-
-extern struct pci_ops sh7751_pci_ops;
-
-struct pci_channel board_pci_channels[] = {
-       { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
-       { NULL, NULL, NULL, 0, 0 },
-};
-EXPORT_SYMBOL(board_pci_channels);
-
-static struct sh4_pci_address_map sh7751_pci_map = {
-       .window0        = {
-               .base   = SH7751_CS3_BASE_ADDR,
-               .size   = 0x04000000,
-       },
-
-       .window1        = {
-               .base   = 0x00000000,   /* Unused */
-               .size   = 0x00000000,   /* Unused */
-       },
-
-       .flags  = SH4_PCIC_NO_RESET,
-};
-
-int __init pcibios_init_platform(void)
-{
-       __set_io_port_base(SH7751_PCI_IO_BASE);
-       return sh7751_pcic_init(&sh7751_pci_map);
-}
-
diff --git a/arch/sh/drivers/pci/ops-sdk7780.c b/arch/sh/drivers/pci/ops-sdk7780.c
deleted file mode 100644 (file)
index 4dcc641..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * linux/arch/sh/drivers/pci/ops-sdk7780.c
- *
- * Copyright (C) 2006  Nobuhiro Iwamatsu
- *
- * PCI initialization for the SDK7780SE03
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <mach/sdk7780.h>
-#include <asm/io.h>
-#include "pci-sh4.h"
-
-/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */
-static char sdk7780_irq_tab[4][16] __initdata = {
-       /* INTA */
-       { 65, 68, 67, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
-       /* INTB */
-       { 66, 65, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
-       /* INTC */
-       { 67, 66, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
-       /* INTD */
-       { 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
-};
-
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
-{
-       return sdk7780_irq_tab[pin-1][slot];
-}
-
-static struct resource sdk7780_io_resource = {
-       .name   = "SH7780_IO",
-       .start  = SH7780_PCI_IO_BASE,
-       .end    = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1,
-       .flags  = IORESOURCE_IO
-};
-
-static struct resource sdk7780_mem_resource = {
-       .name   = "SH7780_mem",
-       .start  = SH7780_PCI_MEMORY_BASE,
-       .end    = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
-       .flags  = IORESOURCE_MEM
-};
-
-struct pci_channel board_pci_channels[] = {
-       { &sh4_pci_ops, &sdk7780_io_resource, &sdk7780_mem_resource, 0, 0xff },
-       { NULL, NULL, NULL, 0, 0 },
-};
-EXPORT_SYMBOL(board_pci_channels);
-
-static struct sh4_pci_address_map sdk7780_pci_map = {
-       .window0        = {
-               .base   = SH7780_CS2_BASE_ADDR,
-               .size   = 0x04000000,
-       },
-       .window1        = {
-               .base   = SH7780_CS3_BASE_ADDR,
-               .size   = 0x04000000,
-       },
-       .flags  = SH4_PCIC_NO_RESET,
-};
-
-int __init pcibios_init_platform(void)
-{
-       printk(KERN_INFO "SH7780 PCI: Finished initializing PCI controller\n");
-       return sh7780_pcic_init(&sdk7780_pci_map);
-}
diff --git a/arch/sh/drivers/pci/ops-se7780.c b/arch/sh/drivers/pci/ops-se7780.c
deleted file mode 100644 (file)
index 3145c62..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * linux/arch/sh/drivers/pci/ops-se7780.c
- *
- * Copyright (C) 2006  Nobuhiro Iwamatsu
- *
- * PCI initialization for the Hitachi UL Solution Engine 7780SE03
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <mach-se/mach/se7780.h>
-#include <asm/io.h>
-#include "pci-sh4.h"
-
-/*
- * IDSEL = AD16  PCI slot
- * IDSEL = AD17  PCI slot
- * IDSEL = AD18  Serial ATA Controller (Silicon Image SiL3512A)
- * IDSEL = AD19  USB Host Controller (NEC uPD7210100A)
- */
-
-/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */
-static char se7780_irq_tab[4][16] __initdata = {
-       /* INTA */
-       { 65, 68, 67, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
-       /* INTB */
-       { 66, 65, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
-       /* INTC */
-       { 67, 66, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
-       /* INTD */
-       { 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
-};
-
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
-{
-       return se7780_irq_tab[pin-1][slot];
-}
-
-static struct resource se7780_io_resource = {
-       .name   = "SH7780_IO",
-       .start  = SH7780_PCI_IO_BASE,
-       .end    = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1,
-       .flags  = IORESOURCE_IO
-};
-
-static struct resource se7780_mem_resource = {
-       .name   = "SH7780_mem",
-       .start  = SH7780_PCI_MEMORY_BASE,
-       .end    = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
-       .flags  = IORESOURCE_MEM
-};
-
-extern struct pci_ops se7780_pci_ops;
-
-struct pci_channel board_pci_channels[] = {
-       { &sh4_pci_ops, &se7780_io_resource, &se7780_mem_resource, 0, 0xff },
-       { NULL, NULL, NULL, 0, 0 },
-};
-EXPORT_SYMBOL(board_pci_channels);
-
-static struct sh4_pci_address_map se7780_pci_map = {
-       .window0        = {
-               .base   = SH7780_CS2_BASE_ADDR,
-               .size   = 0x04000000,
-       },
-       .flags  = SH4_PCIC_NO_RESET,
-};
-
-int __init pcibios_init_platform(void)
-{
-       printk("SH7780 PCI: Finished initialization of the PCI controller\n");
-
-       /*
-        * FPGA PCISEL register initialize
-        *
-        *  CPU  || SLOT1 | SLOT2 | S-ATA | USB
-        *  -------------------------------------
-        *  INTA || INTA  | INTD  |  --   | INTB
-        *  -------------------------------------
-        *  INTB || INTB  | INTA  |  --   | INTC
-        *  -------------------------------------
-        *  INTC || INTC  | INTB  | INTA  |  --
-        *  -------------------------------------
-        *  INTD || INTD  | INTC  |  --   | INTA
-        *  -------------------------------------
-        */
-       ctrl_outw(0x0013, FPGA_PCI_INTSEL1);
-       ctrl_outw(0xE402, FPGA_PCI_INTSEL2);
-
-       return sh7780_pcic_init(&se7780_pci_map);
-}
diff --git a/arch/sh/drivers/pci/ops-sh03.c b/arch/sh/drivers/pci/ops-sh03.c
deleted file mode 100644 (file)
index e1703ff..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * linux/arch/sh/drivers/pci/ops-sh03.c
- *
- * PCI initialization for the Interface CTP/PCI-SH03 board
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include "pci-sh7751.h"
-
-/*
- * Description:  This function sets up and initializes the pcic, sets
- * up the BARS, maps the DRAM into the address space etc, etc.
- */
-int __init pcibios_init_platform(void)
-{
-       __set_io_port_base(SH7751_PCI_IO_BASE);
-       return 1;
-}
-
-static struct resource sh7751_io_resource = {
-       .name   = "SH03 IO",
-       .start  = SH7751_PCI_IO_BASE,
-       .end    = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
-       .flags  = IORESOURCE_IO
-};
-
-static struct resource sh7751_mem_resource = {
-       .name   = "SH03 mem",
-       .start  = SH7751_PCI_MEMORY_BASE,
-       .end    = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
-       .flags  = IORESOURCE_MEM
-};
-
-extern struct pci_ops sh4_pci_ops;
-
-struct pci_channel board_pci_channels[] = {
-       { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
-       { NULL, NULL, NULL, 0, 0 },
-};
-
index 710a3b0306e59739c8b6b9b0e4157fc267dd8bbc..78bebebdc99c33aa3fd1970a3a533f25f0180d81 100644 (file)
@@ -1,22 +1,22 @@
 /*
  * Generic SH-4 / SH-4A PCIC operations (SH7751, SH7780).
  *
- * Copyright (C) 2002 - 2006  Paul Mundt
+ * Copyright (C) 2002 - 2009  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License v2. See the file "COPYING" in the main directory of this archive
  * for more details.
  */
 #include <linux/pci.h>
+#include <linux/io.h>
 #include <asm/addrspace.h>
-#include <asm/io.h>
 #include "pci-sh4.h"
 
 /*
  * Direct access to PCI hardware...
  */
 #define CONFIG_CMD(bus, devfn, where) \
-       P1SEGADDR((bus->number << 16) | (devfn << 8) | (where & ~3))
+       (P1SEG | (bus->number << 16) | (devfn << 8) | (where & ~3))
 
 static DEFINE_SPINLOCK(sh4_pci_lock);
 
@@ -26,6 +26,7 @@ static DEFINE_SPINLOCK(sh4_pci_lock);
 static int sh4_pci_read(struct pci_bus *bus, unsigned int devfn,
                           int where, int size, u32 *val)
 {
+       struct pci_channel *chan = bus->sysdata;
        unsigned long flags;
        u32 data;
 
@@ -34,8 +35,8 @@ static int sh4_pci_read(struct pci_bus *bus, unsigned int devfn,
         * so we must do byte alignment by hand
         */
        spin_lock_irqsave(&sh4_pci_lock, flags);
-       pci_write_reg(CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
-       data = pci_read_reg(SH4_PCIPDR);
+       pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
+       data = pci_read_reg(chan, SH4_PCIPDR);
        spin_unlock_irqrestore(&sh4_pci_lock, flags);
 
        switch (size) {
@@ -63,13 +64,14 @@ static int sh4_pci_read(struct pci_bus *bus, unsigned int devfn,
 static int sh4_pci_write(struct pci_bus *bus, unsigned int devfn,
                         int where, int size, u32 val)
 {
+       struct pci_channel *chan = bus->sysdata;
        unsigned long flags;
        int shift;
        u32 data;
 
        spin_lock_irqsave(&sh4_pci_lock, flags);
-       pci_write_reg(CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
-       data = pci_read_reg(SH4_PCIPDR);
+       pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
+       data = pci_read_reg(chan, SH4_PCIPDR);
        spin_unlock_irqrestore(&sh4_pci_lock, flags);
 
        switch (size) {
@@ -90,7 +92,7 @@ static int sh4_pci_write(struct pci_bus *bus, unsigned int devfn,
                return PCIBIOS_FUNC_NOT_SUPPORTED;
        }
 
-       pci_write_reg(data, SH4_PCIPDR);
+       pci_write_reg(chan, data, SH4_PCIPDR);
 
        return PCIBIOS_SUCCESSFUL;
 }
@@ -104,66 +106,31 @@ struct pci_ops sh4_pci_ops = {
  * Not really related to pci_ops, but it's common and not worth shoving
  * somewhere else for now..
  */
-static unsigned int pci_probe = PCI_PROBE_CONF1;
-
-int __init sh4_pci_check_direct(void)
+int __init sh4_pci_check_direct(struct pci_channel *chan)
 {
        /*
         * Check if configuration works.
         */
-       if (pci_probe & PCI_PROBE_CONF1) {
-               unsigned int tmp = pci_read_reg(SH4_PCIPAR);
-
-               pci_write_reg(P1SEG, SH4_PCIPAR);
+       unsigned int tmp = pci_read_reg(chan, SH4_PCIPAR);
 
-               if (pci_read_reg(SH4_PCIPAR) == P1SEG) {
-                       pci_write_reg(tmp, SH4_PCIPAR);
-                       printk(KERN_INFO "PCI: Using configuration type 1\n");
-                       request_region(PCI_REG(SH4_PCIPAR), 8, "PCI conf1");
+       pci_write_reg(chan, P1SEG, SH4_PCIPAR);
 
-                       return 0;
-               }
-
-               pci_write_reg(tmp, SH4_PCIPAR);
+       if (pci_read_reg(chan, SH4_PCIPAR) == P1SEG) {
+               pci_write_reg(chan, tmp, SH4_PCIPAR);
+               printk(KERN_INFO "PCI: Using configuration type 1\n");
+               request_region(chan->reg_base + SH4_PCIPAR, 8,
+                              "PCI conf1");
+               return 0;
        }
 
-       pr_debug("PCI: pci_check_direct failed\n");
-       return -EINVAL;
-}
+       pci_write_reg(chan, tmp, SH4_PCIPAR);
 
-/* Handle generic fixups */
-static void __init pci_fixup_ide_bases(struct pci_dev *d)
-{
-       int i;
+       printk(KERN_ERR "PCI: %s failed\n", __func__);
 
-       /*
-        * PCI IDE controllers use non-standard I/O port decoding, respect it.
-        */
-       if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
-               return;
-       pr_debug("PCI: IDE base address fixup for %s\n", pci_name(d));
-       for(i = 0; i < 4; i++) {
-               struct resource *r = &d->resource[i];
-
-               if ((r->start & ~0x80) == 0x374) {
-                       r->start |= 2;
-                       r->end = r->start;
-               }
-       }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
-
-char * __devinit pcibios_setup(char *str)
-{
-       if (!strcmp(str, "off")) {
-               pci_probe = 0;
-               return NULL;
-       }
-
-       return str;
+       return -EINVAL;
 }
 
-int __attribute__((weak)) pci_fixup_pcic(void)
+int __attribute__((weak)) pci_fixup_pcic(struct pci_channel *chan)
 {
        /* Nothing to do. */
        return 0;
index 729e38a6fe071c810a42baf9d65ce4e5fdc98cb8..4ce95a001b807059e2362e1e4088ab125b74d22d 100644 (file)
 #include <asm/io.h>
 #include "pci-sh5.h"
 
-static void __init pci_fixup_ide_bases(struct pci_dev *d)
-{
-       int i;
-
-       /*
-        * PCI IDE controllers use non-standard I/O port decoding, respect it.
-        */
-       if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
-               return;
-       printk("PCI: IDE base address fixup for %s\n", pci_name(d));
-       for(i=0; i<4; i++) {
-               struct resource *r = &d->resource[i];
-               if ((r->start & ~0x80) == 0x374) {
-                       r->start |= 2;
-                       r->end = r->start;
-               }
-       }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
-
-char * __devinit pcibios_setup(char *str)
-{
-       return str;
-}
-
 static int sh5pci_read(struct pci_bus *bus, unsigned int devfn, int where,
                        int size, u32 *val)
 {
diff --git a/arch/sh/drivers/pci/ops-sh7785lcr.c b/arch/sh/drivers/pci/ops-sh7785lcr.c
deleted file mode 100644 (file)
index fb0869f..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Author:  Ian DaSilva (idasilva@mvista.com)
- *
- * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * PCI initialization for the Renesas R0P7785LC0011RL board
- * Based on arch/sh/drivers/pci/ops-r7780rp.c
- *
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include "pci-sh4.h"
-
-static char irq_tab[] __initdata = {
-       65, 66, 67, 68,
-};
-
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
-{
-       return irq_tab[slot];
-}
-
-static struct resource sh7785_io_resource = {
-       .name   = "SH7785_IO",
-       .start  = SH7780_PCI_IO_BASE,
-       .end    = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1,
-       .flags  = IORESOURCE_IO
-};
-
-static struct resource sh7785_mem_resource = {
-       .name   = "SH7785_mem",
-       .start  = SH7780_PCI_MEMORY_BASE,
-       .end    = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
-       .flags  = IORESOURCE_MEM
-};
-
-struct pci_channel board_pci_channels[] = {
-       { &sh4_pci_ops, &sh7785_io_resource, &sh7785_mem_resource, 0, 0xff },
-       { NULL, NULL, NULL, 0, 0 },
-};
-EXPORT_SYMBOL(board_pci_channels);
-
-static struct sh4_pci_address_map sh7785_pci_map = {
-       .window0        = {
-#if defined(CONFIG_32BIT)
-               .base   = SH7780_32BIT_DDR_BASE_ADDR,
-               .size   = 0x40000000,
-#else
-               .base   = SH7780_CS0_BASE_ADDR,
-               .size   = 0x20000000,
-#endif
-       },
-
-       .flags  = SH4_PCIC_NO_RESET,
-};
-
-int __init pcibios_init_platform(void)
-{
-       return sh7780_pcic_init(&sh7785_pci_map);
-}
diff --git a/arch/sh/drivers/pci/ops-snapgear.c b/arch/sh/drivers/pci/ops-snapgear.c
deleted file mode 100644 (file)
index 53dd893..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * arch/sh/drivers/pci/ops-snapgear.c
- *
- * Author:  David McCullough <davidm@snapgear.com>
- *
- * Ported to new API by Paul Mundt <lethal@linux-sh.org>
- *
- * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * PCI initialization for the SnapGear boards
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include "pci-sh4.h"
-
-#define SNAPGEAR_PCI_IO                0x4000
-#define SNAPGEAR_PCI_MEM       0xfd000000
-
-/* PCI: default LOCAL memory window sizes (seen from PCI bus) */
-#define SNAPGEAR_LSR0_SIZE    (64*(1<<20)) //64MB
-#define SNAPGEAR_LSR1_SIZE    (64*(1<<20)) //64MB
-
-static struct resource sh7751_io_resource = {
-       .name           = "SH7751 IO",
-       .start          = SNAPGEAR_PCI_IO,
-       .end            = SNAPGEAR_PCI_IO + (64*1024) - 1, /* 64KiB I/O */
-       .flags          = IORESOURCE_IO,
-};
-
-static struct resource sh7751_mem_resource = {
-       .name           = "SH7751 mem",
-       .start          = SNAPGEAR_PCI_MEM,
-       .end            = SNAPGEAR_PCI_MEM + (64*1024*1024) - 1, /* 64MiB mem */
-       .flags          = IORESOURCE_MEM,
-};
-
-struct pci_channel board_pci_channels[] = {
-       { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
-       { 0, }
-};
-
-static struct sh4_pci_address_map sh7751_pci_map = {
-       .window0        = {
-               .base   = SH7751_CS2_BASE_ADDR,
-               .size   = SNAPGEAR_LSR0_SIZE,
-       },
-
-       .window1        = {
-               .base   = SH7751_CS2_BASE_ADDR,
-               .size   = SNAPGEAR_LSR1_SIZE,
-       },
-
-       .flags  = SH4_PCIC_NO_RESET,
-};
-
-/*
- * Initialize the SnapGear PCI interface
- * Setup hardware to be Central Funtion
- * Copy the BSR regs to the PCI interface
- * Setup PCI windows into local RAM
- */
-int __init pcibios_init_platform(void)
-{
-       return sh7751_pcic_init(&sh7751_pci_map);
-}
-
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
-{
-       int irq = -1;
-
-       switch (slot) {
-       case 8:  /* the PCI bridge */ break;
-       case 11: irq = 8;  break; /* USB    */
-       case 12: irq = 11; break; /* PCMCIA */
-       case 13: irq = 5;  break; /* eth0   */
-       case 14: irq = 8;  break; /* eth1   */
-       case 15: irq = 11; break; /* safenet (unused) */
-       }
-
-       printk("PCI: Mapping SnapGear IRQ for slot %d, pin %c to irq %d\n",
-              slot, pin - 1 + 'A', irq);
-
-       return irq;
-}
-
-void __init pcibios_fixup(void)
-{
-       /* Nothing to fixup .. */
-}
diff --git a/arch/sh/drivers/pci/pci-auto.c b/arch/sh/drivers/pci/pci-auto.c
deleted file mode 100644 (file)
index cf48b12..0000000
+++ /dev/null
@@ -1,545 +0,0 @@
-/*
- * PCI autoconfiguration library
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * Copyright 2000, 2001 MontaVista Software Inc.
- * Copyright 2001 Bradley D. LaRonde <brad@ltc.com>
- * Copyright 2003 Paul Mundt <lethal@linux-sh.org>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-/*
- * Modified for MIPS by Jun Sun, jsun@mvista.com
- *
- * . Simplify the interface between pci_auto and the rest: a single function.
- * . Assign resources from low address to upper address.
- * . change most int to u32.
- *
- * Further modified to include it as mips generic code, ppopov@mvista.com.
- *
- * 2001-10-26  Bradley D. LaRonde <brad@ltc.com>
- * - Add a top_bus argument to the "early config" functions so that
- *   they can set a fake parent bus pointer to convince the underlying
- *   pci ops to use type 1 configuration for sub busses.
- * - Set bridge base and limit registers correctly.
- * - Align io and memory base properly before and after bridge setup.
- * - Don't fall through to pci_setup_bars for bridge.
- * - Reformat the debug output to look more like lspci's output.
- *
- * Cloned for SuperH by M. R. Brown, mrbrown@0xd6.org
- *
- * 2003-08-05  Paul Mundt <lethal@linux-sh.org>
- * - Don't update the BAR values on systems that already have valid addresses
- *   and don't want these updated for whatever reason, by way of a new config
- *   option check. However, we still read in the old BAR values so that they
- *   can still be reported through the debug output.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-
-#define        DEBUG
-#ifdef DEBUG
-#define        DBG(x...)       printk(x)
-#else
-#define        DBG(x...)
-#endif
-
-/*
- * These functions are used early on before PCI scanning is done
- * and all of the pci_dev and pci_bus structures have been created.
- */
-static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
-       int top_bus, int busnr, int devfn)
-{
-       static struct pci_dev dev;
-       static struct pci_bus bus;
-
-       dev.bus = &bus;
-       dev.sysdata = hose;
-       dev.devfn = devfn;
-       bus.number = busnr;
-       bus.ops = hose->pci_ops;
-
-       if(busnr != top_bus)
-               /* Fake a parent bus structure. */
-               bus.parent = &bus;
-       else
-               bus.parent = NULL;
-
-       return &dev;
-}
-
-#define EARLY_PCI_OP(rw, size, type)                                   \
-static int early_##rw##_config_##size(struct pci_channel *hose,                \
-       int top_bus, int bus, int devfn, int offset, type value)        \
-{                                                                      \
-       return pci_##rw##_config_##size(                                \
-               fake_pci_dev(hose, top_bus, bus, devfn),                \
-               offset, value);                                         \
-}
-
-EARLY_PCI_OP(read, byte, u8 *)
-EARLY_PCI_OP(read, word, u16 *)
-EARLY_PCI_OP(read, dword, u32 *)
-EARLY_PCI_OP(write, byte, u8)
-EARLY_PCI_OP(write, word, u16)
-EARLY_PCI_OP(write, dword, u32)
-
-static struct resource *io_resource_inuse;
-static struct resource *mem_resource_inuse;
-
-static u32 pciauto_lower_iospc;
-static u32 pciauto_upper_iospc;
-
-static u32 pciauto_lower_memspc;
-static u32 pciauto_upper_memspc;
-
-static void __init
-pciauto_setup_bars(struct pci_channel *hose,
-                  int top_bus,
-                  int current_bus,
-                  int pci_devfn,
-                  int bar_limit)
-{
-       u32 bar_response, bar_size, bar_value;
-       u32 bar, addr_mask, bar_nr = 0;
-       u32 * upper_limit;
-       u32 * lower_limit;
-       int found_mem64 = 0;
-
-       for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) {
-               u32 bar_addr;
-
-               /* Read the old BAR value */
-               early_read_config_dword(hose, top_bus,
-                                       current_bus,
-                                       pci_devfn,
-                                       bar,
-                                       &bar_addr);
-
-               /* Tickle the BAR and get the response */
-               early_write_config_dword(hose, top_bus,
-                                        current_bus,
-                                        pci_devfn,
-                                        bar,
-                                        0xffffffff);
-
-               early_read_config_dword(hose, top_bus,
-                                       current_bus,
-                                       pci_devfn,
-                                       bar,
-                                       &bar_response);
-
-               /*
-                * Write the old BAR value back out, only update the BAR
-                * if we implicitly want resources to be updated, which
-                * is done by the generic code further down. -- PFM.
-                */
-               early_write_config_dword(hose, top_bus,
-                                        current_bus,
-                                        pci_devfn,
-                                        bar,
-                                        bar_addr);
-
-               /* If BAR is not implemented go to the next BAR */
-               if (!bar_response)
-                       continue;
-
-               /*
-                * Workaround for a BAR that doesn't use its upper word,
-                * like the ALi 1535D+ PCI DC-97 Controller Modem (M5457).
-                * bdl <brad@ltc.com>
-                */
-               if (!(bar_response & 0xffff0000))
-                       bar_response |= 0xffff0000;
-
-retry:
-               /* Check the BAR type and set our address mask */
-               if (bar_response & PCI_BASE_ADDRESS_SPACE) {
-                       addr_mask = PCI_BASE_ADDRESS_IO_MASK;
-                       upper_limit = &pciauto_upper_iospc;
-                       lower_limit = &pciauto_lower_iospc;
-                       DBG("        I/O");
-               } else {
-                       if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
-                           PCI_BASE_ADDRESS_MEM_TYPE_64)
-                               found_mem64 = 1;
-
-                       addr_mask = PCI_BASE_ADDRESS_MEM_MASK;
-                       upper_limit = &pciauto_upper_memspc;
-                       lower_limit = &pciauto_lower_memspc;
-                       DBG("        Mem");
-               }
-
-
-               /* Calculate requested size */
-               bar_size = ~(bar_response & addr_mask) + 1;
-
-               /* Allocate a base address */
-               bar_value = ((*lower_limit - 1) & ~(bar_size - 1)) + bar_size;
-
-               if ((bar_value + bar_size) > *upper_limit) {
-                       if (bar_response & PCI_BASE_ADDRESS_SPACE) {
-                               if (io_resource_inuse->child) {
-                                       io_resource_inuse =
-                                               io_resource_inuse->child;
-                                       pciauto_lower_iospc =
-                                               io_resource_inuse->start;
-                                       pciauto_upper_iospc =
-                                               io_resource_inuse->end + 1;
-                                       goto retry;
-                               }
-
-                       } else {
-                               if (mem_resource_inuse->child) {
-                                       mem_resource_inuse =
-                                               mem_resource_inuse->child;
-                                       pciauto_lower_memspc =
-                                               mem_resource_inuse->start;
-                                       pciauto_upper_memspc =
-                                               mem_resource_inuse->end + 1;
-                                       goto retry;
-                               }
-                       }
-                       DBG(" unavailable -- skipping, value %x size %x\n",
-                                       bar_value, bar_size);
-                       continue;
-               }
-
-               if (bar_value < *lower_limit || (bar_value + bar_size) >= *upper_limit) {
-                       DBG(" unavailable -- skipping, value %x size %x\n",
-                                       bar_value, bar_size);
-                       continue;
-               }
-
-#ifdef CONFIG_PCI_AUTO_UPDATE_RESOURCES
-               /* Write it out and update our limit */
-               early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
-                                        bar, bar_value);
-#endif
-
-               *lower_limit = bar_value + bar_size;
-
-               /*
-                * If we are a 64-bit decoder then increment to the
-                * upper 32 bits of the bar and force it to locate
-                * in the lower 4GB of memory.
-                */
-               if (found_mem64) {
-                       bar += 4;
-                       early_write_config_dword(hose, top_bus,
-                                                current_bus,
-                                                pci_devfn,
-                                                bar,
-                                                0x00000000);
-               }
-
-               DBG(" at 0x%.8x [size=0x%x]\n", bar_value, bar_size);
-
-               bar_nr++;
-       }
-
-}
-
-static void __init
-pciauto_prescan_setup_bridge(struct pci_channel *hose,
-                            int top_bus,
-                            int current_bus,
-                            int pci_devfn,
-                            int sub_bus)
-{
-       /* Configure bus number registers */
-       early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
-                               PCI_PRIMARY_BUS, current_bus);
-       early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
-                               PCI_SECONDARY_BUS, sub_bus + 1);
-       early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
-                               PCI_SUBORDINATE_BUS, 0xff);
-
-       /* Align memory and I/O to 1MB and 4KB boundaries. */
-       pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1))
-               & ~(0x100000 - 1);
-       pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1))
-               & ~(0x1000 - 1);
-
-       /* Set base (lower limit) of address range behind bridge. */
-       early_write_config_word(hose, top_bus, current_bus, pci_devfn,
-               PCI_MEMORY_BASE, pciauto_lower_memspc >> 16);
-       early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
-               PCI_IO_BASE, (pciauto_lower_iospc & 0x0000f000) >> 8);
-       early_write_config_word(hose, top_bus, current_bus, pci_devfn,
-               PCI_IO_BASE_UPPER16, pciauto_lower_iospc >> 16);
-
-       /* We don't support prefetchable memory for now, so disable */
-       early_write_config_word(hose, top_bus, current_bus, pci_devfn,
-                               PCI_PREF_MEMORY_BASE, 0);
-       early_write_config_word(hose, top_bus, current_bus, pci_devfn,
-                               PCI_PREF_MEMORY_LIMIT, 0);
-}
-
-static void __init
-pciauto_postscan_setup_bridge(struct pci_channel *hose,
-                             int top_bus,
-                             int current_bus,
-                             int pci_devfn,
-                             int sub_bus)
-{
-       u32 temp;
-
-       /*
-        * [jsun] we always bump up baselines a little, so that if there
-        * nothing behind P2P bridge, we don't wind up overlapping IO/MEM
-        * spaces.
-        */
-       pciauto_lower_memspc += 1;
-       pciauto_lower_iospc += 1;
-
-       /* Configure bus number registers */
-       early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
-                               PCI_SUBORDINATE_BUS, sub_bus);
-
-       /* Set upper limit of address range behind bridge. */
-       early_write_config_word(hose, top_bus, current_bus, pci_devfn,
-               PCI_MEMORY_LIMIT, pciauto_lower_memspc >> 16);
-       early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
-               PCI_IO_LIMIT, (pciauto_lower_iospc & 0x0000f000) >> 8);
-       early_write_config_word(hose, top_bus, current_bus, pci_devfn,
-               PCI_IO_LIMIT_UPPER16, pciauto_lower_iospc >> 16);
-
-       /* Align memory and I/O to 1MB and 4KB boundaries. */
-       pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1))
-               & ~(0x100000 - 1);
-       pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1))
-               & ~(0x1000 - 1);
-
-       /* Enable memory and I/O accesses, enable bus master */
-       early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
-               PCI_COMMAND, &temp);
-       early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
-               PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY
-               | PCI_COMMAND_MASTER);
-}
-
-static void __init
-pciauto_prescan_setup_cardbus_bridge(struct pci_channel *hose,
-                       int top_bus,
-                       int current_bus,
-                       int pci_devfn,
-                       int sub_bus)
-{
-       /* Configure bus number registers */
-       early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
-                               PCI_PRIMARY_BUS, current_bus);
-       early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
-                               PCI_SECONDARY_BUS, sub_bus + 1);
-       early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
-                               PCI_SUBORDINATE_BUS, 0xff);
-
-       /* Align memory and I/O to 4KB and 4 byte boundaries. */
-       pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1))
-               & ~(0x1000 - 1);
-       pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1))
-               & ~(0x4 - 1);
-
-       early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
-               PCI_CB_MEMORY_BASE_0, pciauto_lower_memspc);
-       early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
-               PCI_CB_IO_BASE_0, pciauto_lower_iospc);
-}
-
-static void __init
-pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose,
-                       int top_bus,
-                       int current_bus,
-                       int pci_devfn,
-                       int sub_bus)
-{
-       u32 temp;
-
-       /*
-        * [jsun] we always bump up baselines a little, so that if there
-        * nothing behind P2P bridge, we don't wind up overlapping IO/MEM
-        * spaces.
-        */
-       pciauto_lower_memspc += 1;
-       pciauto_lower_iospc += 1;
-
-       /*
-        * Configure subordinate bus number.  The PCI subsystem
-        * bus scan will renumber buses (reserving three additional
-        * for this PCI<->CardBus bridge for the case where a CardBus
-        * adapter contains a P2P or CB2CB bridge.
-        */
-
-       early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
-                               PCI_SUBORDINATE_BUS, sub_bus);
-
-       /*
-        * Reserve an additional 4MB for mem space and 16KB for
-        * I/O space.  This should cover any additional space
-        * requirement of unusual CardBus devices with
-        * additional bridges that can consume more address space.
-        *
-        * Although pcmcia-cs currently will reprogram bridge
-        * windows, the goal is to add an option to leave them
-        * alone and use the bridge window ranges as the regions
-        * that are searched for free resources upon hot-insertion
-        * of a device.  This will allow a PCI<->CardBus bridge
-        * configured by this routine to happily live behind a
-        * P2P bridge in a system.
-        */
-       /* Align memory and I/O to 4KB and 4 byte boundaries. */
-       pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1))
-               & ~(0x1000 - 1);
-       pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1))
-               & ~(0x4 - 1);
-       /* Set up memory and I/O filter limits, assume 32-bit I/O space */
-       early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
-               PCI_CB_MEMORY_LIMIT_0, pciauto_lower_memspc - 1);
-       early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
-               PCI_CB_IO_LIMIT_0, pciauto_lower_iospc - 1);
-
-       /* Enable memory and I/O accesses, enable bus master */
-       early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
-               PCI_COMMAND, &temp);
-       early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
-               PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-               PCI_COMMAND_MASTER);
-}
-
-#define        PCIAUTO_IDE_MODE_MASK           0x05
-
-static int __init
-pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus)
-{
-       int sub_bus;
-       u32 pci_devfn, pci_class, cmdstat, found_multi=0;
-       unsigned short vid, did;
-       unsigned char header_type;
-       int devfn_start = 0;
-       int devfn_stop = 0xff;
-
-       sub_bus = current_bus;
-
-       if (hose->first_devfn)
-               devfn_start = hose->first_devfn;
-       if (hose->last_devfn)
-               devfn_stop = hose->last_devfn;
-
-       for (pci_devfn=devfn_start; pci_devfn<devfn_stop; pci_devfn++) {
-
-               if (PCI_FUNC(pci_devfn) && !found_multi)
-                       continue;
-
-               early_read_config_word(hose, top_bus, current_bus, pci_devfn,
-                                      PCI_VENDOR_ID, &vid);
-
-               if (vid == 0xffff) continue;
-
-               early_read_config_byte(hose, top_bus, current_bus, pci_devfn,
-                                      PCI_HEADER_TYPE, &header_type);
-
-               if (!PCI_FUNC(pci_devfn))
-                       found_multi = header_type & 0x80;
-
-               early_read_config_word(hose, top_bus, current_bus, pci_devfn,
-                                      PCI_DEVICE_ID, &did);
-
-               early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
-                                       PCI_CLASS_REVISION, &pci_class);
-
-               DBG("%.2x:%.2x.%x Class %.4x: %.4x:%.4x",
-                       current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn),
-                       pci_class >> 16, vid, did);
-               if (pci_class & 0xff)
-                       DBG(" (rev %.2x)", pci_class & 0xff);
-               DBG("\n");
-
-               if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) {
-                       DBG("        Bridge: primary=%.2x, secondary=%.2x\n",
-                               current_bus, sub_bus + 1);
-                       pciauto_prescan_setup_bridge(hose, top_bus, current_bus,
-                                                    pci_devfn, sub_bus);
-                       DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n",
-                               sub_bus + 1,
-                               pciauto_lower_iospc, pciauto_lower_memspc);
-                       sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1);
-                       DBG("Back to bus %.2x\n", current_bus);
-                       pciauto_postscan_setup_bridge(hose, top_bus, current_bus,
-                                                       pci_devfn, sub_bus);
-                       continue;
-               } else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) {
-                       DBG("  CARDBUS  Bridge: primary=%.2x, secondary=%.2x\n",
-                               current_bus, sub_bus + 1);
-                       DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn));
-                       /* Place CardBus Socket/ExCA registers */
-                       pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_0);
-
-                       pciauto_prescan_setup_cardbus_bridge(hose, top_bus,
-                                       current_bus, pci_devfn, sub_bus);
-
-                       DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n",
-                               sub_bus + 1,
-                               pciauto_lower_iospc, pciauto_lower_memspc);
-                       sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1);
-                       DBG("Back to bus %.2x, sub_bus is %x\n", current_bus, sub_bus);
-                       pciauto_postscan_setup_cardbus_bridge(hose, top_bus,
-                                       current_bus, pci_devfn, sub_bus);
-                       continue;
-               } else if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) {
-
-                       unsigned char prg_iface;
-
-                       early_read_config_byte(hose, top_bus, current_bus,
-                               pci_devfn, PCI_CLASS_PROG, &prg_iface);
-                       if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
-                               DBG("Skipping legacy mode IDE controller\n");
-                               continue;
-                       }
-               }
-
-               /*
-                * Found a peripheral, enable some standard
-                * settings
-                */
-               early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
-                                       PCI_COMMAND, &cmdstat);
-               early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
-                                        PCI_COMMAND, cmdstat | PCI_COMMAND_IO |
-                                        PCI_COMMAND_MEMORY |
-                                        PCI_COMMAND_MASTER);
-               early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
-                                       PCI_LATENCY_TIMER, 0x80);
-
-               /* Allocate PCI I/O and/or memory space */
-               pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_5);
-       }
-       return sub_bus;
-}
-
-int __init
-pciauto_assign_resources(int busno, struct pci_channel *hose)
-{
-       /* setup resource limits */
-       io_resource_inuse = hose->io_resource;
-       mem_resource_inuse = hose->mem_resource;
-
-       pciauto_lower_iospc = io_resource_inuse->start;
-       pciauto_upper_iospc = io_resource_inuse->end + 1;
-       pciauto_lower_memspc = mem_resource_inuse->start;
-       pciauto_upper_memspc = mem_resource_inuse->end + 1;
-       DBG("Autoconfig PCI channel 0x%p\n", hose);
-       DBG("Scanning bus %.2x, I/O 0x%.8x:0x%.8x, Mem 0x%.8x:0x%.8x\n",
-               busno, pciauto_lower_iospc, pciauto_upper_iospc, 
-               pciauto_lower_memspc, pciauto_upper_memspc);
-
-       return pciauto_bus_scan(hose, busno, busno);
-}
diff --git a/arch/sh/drivers/pci/pci-dreamcast.c b/arch/sh/drivers/pci/pci-dreamcast.c
new file mode 100644 (file)
index 0000000..210f9d4
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * PCI support for the Sega Dreamcast
+ *
+ * Copyright (C) 2001, 2002  M. R. Brown
+ * Copyright (C) 2002, 2003  Paul Mundt
+ *
+ * This file originally bore the message (with enclosed-$):
+ *     Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp
+ *     Dreamcast PCI: Supports SEGA Broadband Adaptor only.
+ *
+ * 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.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <mach/pci.h>
+
+static struct resource gapspci_io_resource = {
+       .name   = "GAPSPCI IO",
+       .start  = GAPSPCI_BBA_CONFIG,
+       .end    = GAPSPCI_BBA_CONFIG + GAPSPCI_BBA_CONFIG_SIZE - 1,
+       .flags  = IORESOURCE_IO,
+};
+
+static struct resource gapspci_mem_resource = {
+       .name   = "GAPSPCI mem",
+       .start  = GAPSPCI_DMA_BASE,
+       .end    = GAPSPCI_DMA_BASE + GAPSPCI_DMA_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct pci_channel dreamcast_pci_controller = {
+       .pci_ops        = &gapspci_pci_ops,
+       .io_resource    = &gapspci_io_resource,
+       .io_offset      = 0x00000000,
+       .mem_resource   = &gapspci_mem_resource,
+       .mem_offset     = 0x00000000,
+};
+
+/*
+ * gapspci init
+ */
+
+static int __init gapspci_init(void)
+{
+       char idbuf[16];
+       int i;
+
+       /*
+        * FIXME: All of this wants documenting to some degree,
+        * even some basic register definitions would be nice.
+        *
+        * I haven't seen anything this ugly since.. maple.
+        */
+
+       for (i=0; i<16; i++)
+               idbuf[i] = inb(GAPSPCI_REGS+i);
+
+       if (strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16))
+               return -ENODEV;
+
+       outl(0x5a14a501, GAPSPCI_REGS+0x18);
+
+       for (i=0; i<1000000; i++)
+               cpu_relax();
+
+       if (inl(GAPSPCI_REGS+0x18) != 1)
+               return -EINVAL;
+
+       outl(0x01000000, GAPSPCI_REGS+0x20);
+       outl(0x01000000, GAPSPCI_REGS+0x24);
+
+       outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28);
+       outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c);
+
+       outl(1, GAPSPCI_REGS+0x14);
+       outl(1, GAPSPCI_REGS+0x34);
+
+       /* Setting Broadband Adapter */
+       outw(0xf900, GAPSPCI_BBA_CONFIG+0x06);
+       outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30);
+       outb(0x00, GAPSPCI_BBA_CONFIG+0x3c);
+       outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d);
+       outw(0x0006, GAPSPCI_BBA_CONFIG+0x04);
+       outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10);
+       outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14);
+
+       register_pci_controller(&dreamcast_pci_controller);
+
+       return 0;
+}
+arch_initcall(gapspci_init);
index a83dcf70c13b1734a2b936f8622a70f5776624d8..3d5296cde622d2ccd27af59ec75dd73650b9388d 100644 (file)
   #define SH4_PCIPDTR_PB0        0x000000001   /* Port 0 Enable */
 #define SH4_PCIPDR             0x220           /* Port IO Data Register */
 
-/* Flags */
-#define SH4_PCIC_NO_RESET      0x0001
-
 /* arch/sh/kernel/drivers/pci/ops-sh4.c */
 extern struct pci_ops sh4_pci_ops;
-int sh4_pci_check_direct(void);
-int pci_fixup_pcic(void);
+int sh4_pci_check_direct(struct pci_channel *chan);
+int pci_fixup_pcic(struct pci_channel *chan);
 
 struct sh4_pci_address_space {
        unsigned long base;
@@ -165,16 +162,18 @@ struct sh4_pci_address_space {
 struct sh4_pci_address_map {
        struct sh4_pci_address_space window0;
        struct sh4_pci_address_space window1;
-       unsigned long flags;
 };
 
-static inline void pci_write_reg(unsigned long val, unsigned long reg)
+static inline void pci_write_reg(struct pci_channel *chan,
+                                unsigned long val, unsigned long reg)
 {
-       ctrl_outl(val, PCI_REG(reg));
+       ctrl_outl(val, chan->reg_base + reg);
 }
 
-static inline unsigned long pci_read_reg(unsigned long reg)
+static inline unsigned long pci_read_reg(struct pci_channel *chan,
+                                        unsigned long reg)
 {
-       return ctrl_inl(PCI_REG(reg));
+       return ctrl_inl(chan->reg_base + reg);
 }
+
 #endif /* __PCI_SH4_H */
index 7a97438762c836f5860e3854e95ea243ae0b9ac1..873ed2b4405575a53bcb2f0c3b453ebea0cfc473 100644 (file)
@@ -89,8 +89,21 @@ static irqreturn_t pcish5_serr_irq(int irq, void *dev_id)
        return IRQ_NONE;
 }
 
-int __init sh5pci_init(unsigned long memStart, unsigned long memSize)
+static struct resource sh5_io_resource = { /* place holder */ };
+static struct resource sh5_mem_resource = { /* place holder */ };
+
+static struct pci_channel sh5pci_controller = {
+       .pci_ops                = &sh5_pci_ops,
+       .mem_resource           = &sh5_mem_resource,
+       .mem_offset             = 0x00000000,
+       .io_resource            = &sh5_io_resource,
+       .io_offset              = 0x00000000,
+};
+
+static int __init sh5pci_init(void)
 {
+       unsigned long memStart = __pa(memory_start);
+       unsigned long memSize = __pa(memory_end) - memStart;
        u32 lsr0;
        u32 uval;
 
@@ -106,12 +119,12 @@ int __init sh5pci_init(unsigned long memStart, unsigned long memSize)
                 return -EINVAL;
         }
 
-       pcicr_virt = onchip_remap(SH5PCI_ICR_BASE, 1024, "PCICR");
+       pcicr_virt = (unsigned long)ioremap_nocache(SH5PCI_ICR_BASE, 1024);
        if (!pcicr_virt) {
                panic("Unable to remap PCICR\n");
        }
 
-       PCI_IO_AREA = onchip_remap(SH5PCI_IO_BASE, 0x10000, "PCIIO");
+       PCI_IO_AREA = (unsigned long)ioremap_nocache(SH5PCI_IO_BASE, 0x10000);
        if (!PCI_IO_AREA) {
                panic("Unable to remap PCIIO\n");
        }
@@ -197,32 +210,14 @@ int __init sh5pci_init(unsigned long memStart, unsigned long memSize)
         SH5PCI_WRITE(AINTM, ~0);
         SH5PCI_WRITE(PINTM, ~0);
 
-       return 0;
-}
+       sh5_io_resource.start = PCI_IO_AREA;
+       sh5_io_resource.end = PCI_IO_AREA + 0x10000;
 
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
-{
-       struct pci_dev *dev = bus->self;
-       int i;
-
-       if (dev) {
-               for (i= 0; i < 3; i++) {
-                       bus->resource[i] =
-                               &dev->resource[PCI_BRIDGE_RESOURCES+i];
-                       bus->resource[i]->name = bus->name;
-               }
-               bus->resource[0]->flags |= IORESOURCE_IO;
-               bus->resource[1]->flags |= IORESOURCE_MEM;
-
-               /* For now, propagate host limits to the bus;
-                * we'll adjust them later. */
-               bus->resource[0]->end = 64*1024 - 1 ;
-               bus->resource[1]->end = PCIBIOS_MIN_MEM+(256*1024*1024)-1;
-               bus->resource[0]->start = PCIBIOS_MIN_IO;
-               bus->resource[1]->start = PCIBIOS_MIN_MEM;
-
-               /* Turn off downstream PF memory address range by default */
-               bus->resource[2]->start = 1024*1024;
-               bus->resource[2]->end = bus->resource[2]->start - 1;
-       }
+       sh5_mem_resource.start = memStart;
+       sh5_mem_resource.end = memStart + memSize;
+
+       register_pci_controller(&sh5pci_controller);
+
+       return 0;
 }
+arch_initcall(sh5pci_init);
index 7cff3fc04d30a2fb29d2079dfbc6062723abb1eb..f277628221f3c04c4d23a930f24d118d5a8cda7e 100644 (file)
@@ -107,7 +107,4 @@ extern unsigned long pcicr_virt;
 
 extern struct pci_ops sh5_pci_ops;
 
-/* arch/sh/drivers/pci/pci-sh5.c */
-int sh5pci_init(unsigned long memStart, unsigned long memSize);
-
 #endif /* __PCI_SH5_H */
index 3065eb184f01c72c8b5e7f5a1ec4a177e4ce3def..70c1999a0ec4c4494a5dd33c263a03d6aabd74f2 100644 (file)
 /*
- *     Low-Level PCI Support for the SH7751
+ * Low-Level PCI Support for the SH7751
  *
- *  Dustin McIntire (dustin@sensoria.com)
- *     Derived from arch/i386/kernel/pci-*.c which bore the message:
- *     (c) 1999--2000 Martin Mares <mj@ucw.cz>
+ *  Copyright (C) 2003 - 2009  Paul Mundt
+ *  Copyright (C) 2001  Dustin McIntire
  *
- *  Ported to the new API by Paul Mundt <lethal@linux-sh.org>
- *  With cleanup by Paul van Gool <pvangool@mimotech.com>
- *
- *  May be copied or modified under the terms of the GNU General Public
- *  License.  See linux/COPYING for more information.
+ *  With cleanup by Paul van Gool <pvangool@mimotech.com>, 2003.
  *
+ * 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.
  */
-#undef DEBUG
-
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/types.h>
 #include <linux/errno.h>
-#include <linux/delay.h>
+#include <linux/io.h>
 #include "pci-sh4.h"
 #include <asm/addrspace.h>
-#include <asm/io.h>
 
-/*
- * Initialization. Try all known PCI access methods. Note that we support
- * using both PCI BIOS and direct access: in such cases, we use I/O ports
- * to access config space.
- *
- * Note that the platform specific initialization (BSC registers, and memory
- * space mapping) will be called via the platform defined function
- * pcibios_init_platform().
- */
-static int __init sh7751_pci_init(void)
+static int __init __area_sdram_check(struct pci_channel *chan,
+                                    unsigned int area)
 {
-       unsigned int id;
-       int ret;
-
-       pr_debug("PCI: Starting intialization.\n");
+       unsigned long word;
 
-       /* check for SH7751/SH7751R hardware */
-       id = pci_read_reg(SH7751_PCICONF0);
-       if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) &&
-           id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) {
-               pr_debug("PCI: This is not an SH7751(R) (%x)\n", id);
-               return -ENODEV;
-       }
-
-       if ((ret = sh4_pci_check_direct()) != 0)
-               return ret;
-
-       return pcibios_init_platform();
-}
-subsys_initcall(sh7751_pci_init);
-
-static int __init __area_sdram_check(unsigned int area)
-{
-       u32 word;
-
-       word = ctrl_inl(SH7751_BCR1);
+       word = __raw_readl(SH7751_BCR1);
        /* check BCR for SDRAM in area */
        if (((word >> area) & 1) == 0) {
-               printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%x\n",
+               printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%lx\n",
                       area, word);
                return 0;
        }
-       pci_write_reg(word, SH4_PCIBCR1);
+       pci_write_reg(chan, word, SH4_PCIBCR1);
 
-       word = (u16)ctrl_inw(SH7751_BCR2);
+       word = __raw_readw(SH7751_BCR2);
        /* check BCR2 for 32bit SDRAM interface*/
        if (((word >> (area << 1)) & 0x3) != 0x3) {
-               printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%x\n",
+               printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%lx\n",
                       area, word);
                return 0;
        }
-       pci_write_reg(word, SH4_PCIBCR2);
+       pci_write_reg(chan, word, SH4_PCIBCR2);
 
        return 1;
 }
 
-int __init sh7751_pcic_init(struct sh4_pci_address_map *map)
+static struct resource sh7751_io_resource = {
+       .name   = "SH7751_IO",
+       .start  = SH7751_PCI_IO_BASE,
+       .end    = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
+       .flags  = IORESOURCE_IO
+};
+
+static struct resource sh7751_mem_resource = {
+       .name   = "SH7751_mem",
+       .start  = SH7751_PCI_MEMORY_BASE,
+       .end    = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
+       .flags  = IORESOURCE_MEM
+};
+
+static struct pci_channel sh7751_pci_controller = {
+       .pci_ops        = &sh4_pci_ops,
+       .mem_resource   = &sh7751_mem_resource,
+       .mem_offset     = 0x00000000,
+       .io_resource    = &sh7751_io_resource,
+       .io_offset      = 0x00000000,
+       .io_map_base    = SH7751_PCI_IO_BASE,
+};
+
+static struct sh4_pci_address_map sh7751_pci_map = {
+       .window0        = {
+               .base   = SH7751_CS3_BASE_ADDR,
+               .size   = 0x04000000,
+       },
+};
+
+static int __init sh7751_pci_init(void)
 {
-       u32 reg;
-       u32 word;
+       struct pci_channel *chan = &sh7751_pci_controller;
+       unsigned int id;
+       u32 word, reg;
+       int ret;
+
+       printk(KERN_NOTICE "PCI: Starting intialization.\n");
+
+       chan->reg_base = 0xfe200000;
+
+       /* check for SH7751/SH7751R hardware */
+       id = pci_read_reg(chan, SH7751_PCICONF0);
+       if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) &&
+           id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) {
+               pr_debug("PCI: This is not an SH7751(R) (%x)\n", id);
+               return -ENODEV;
+       }
+
+       if ((ret = sh4_pci_check_direct(chan)) != 0)
+               return ret;
 
        /* Set the BCR's to enable PCI access */
        reg = ctrl_inl(SH7751_BCR1);
@@ -90,25 +102,10 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map)
        ctrl_outl(reg, SH7751_BCR1);
 
        /* Turn the clocks back on (not done in reset)*/
-       pci_write_reg(0, SH4_PCICLKR);
+       pci_write_reg(chan, 0, SH4_PCICLKR);
        /* Clear Powerdown IRQ's (not done in reset) */
        word = SH4_PCIPINT_D3 | SH4_PCIPINT_D0;
-       pci_write_reg(word, SH4_PCIPINT);
-
-       /*
-        * This code is unused for some boards as it is done in the
-        * bootloader and doing it here means the MAC addresses loaded
-        * by the bootloader get lost.
-        */
-       if (!(map->flags & SH4_PCIC_NO_RESET)) {
-               /* toggle PCI reset pin */
-               word = SH4_PCICR_PREFIX | SH4_PCICR_PRST;
-               pci_write_reg(word, SH4_PCICR);
-               /* Wait for a long time... not 1 sec. but long enough */
-               mdelay(100);
-               word = SH4_PCICR_PREFIX;
-               pci_write_reg(word, SH4_PCICR);
-       }
+       pci_write_reg(chan, word, SH4_PCIPINT);
 
        /* set the command/status bits to:
         * Wait Cycle Control + Parity Enable + Bus Master +
@@ -116,89 +113,75 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map)
         */
        word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER |
               SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES;
-       pci_write_reg(word, SH7751_PCICONF1);
+       pci_write_reg(chan, word, SH7751_PCICONF1);
 
        /* define this host as the host bridge */
        word = PCI_BASE_CLASS_BRIDGE << 24;
-       pci_write_reg(word, SH7751_PCICONF2);
+       pci_write_reg(chan, word, SH7751_PCICONF2);
 
        /* Set IO and Mem windows to local address
         * Make PCI and local address the same for easy 1 to 1 mapping
-        * Window0 = map->window0.size @ non-cached area base = SDRAM
-        * Window1 = map->window1.size @ cached area base = SDRAM
         */
-       word = map->window0.size - 1;
-       pci_write_reg(word, SH4_PCILSR0);
-       word = map->window1.size - 1;
-       pci_write_reg(word, SH4_PCILSR1);
+       word = sh7751_pci_map.window0.size - 1;
+       pci_write_reg(chan, word, SH4_PCILSR0);
        /* Set the values on window 0 PCI config registers */
-       word = P2SEGADDR(map->window0.base);
-       pci_write_reg(word, SH4_PCILAR0);
-       pci_write_reg(word, SH7751_PCICONF5);
-       /* Set the values on window 1 PCI config registers */
-       word =  PHYSADDR(map->window1.base);
-       pci_write_reg(word, SH4_PCILAR1);
-       pci_write_reg(word, SH7751_PCICONF6);
+       word = P2SEGADDR(sh7751_pci_map.window0.base);
+       pci_write_reg(chan, word, SH4_PCILAR0);
+       pci_write_reg(chan, word, SH7751_PCICONF5);
 
        /* Set the local 16MB PCI memory space window to
         * the lowest PCI mapped address
         */
-       word = PCIBIOS_MIN_MEM & SH4_PCIMBR_MASK;
+       word = chan->mem_resource->start & SH4_PCIMBR_MASK;
        pr_debug("PCI: Setting upper bits of Memory window to 0x%x\n", word);
-       pci_write_reg(word , SH4_PCIMBR);
-
-       /* Map IO space into PCI IO window
-        * The IO window is 64K-PCIBIOS_MIN_IO in size
-        * IO addresses will be translated to the
-        * PCI IO window base address
-        */
-       pr_debug("PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n",
-                PCIBIOS_MIN_IO, (64 << 10),
-                SH7751_PCI_IO_BASE + PCIBIOS_MIN_IO);
+       pci_write_reg(chan, word , SH4_PCIMBR);
 
        /* Make sure the MSB's of IO window are set to access PCI space
         * correctly */
-       word = PCIBIOS_MIN_IO & SH4_PCIIOBR_MASK;
+       word = chan->io_resource->start & SH4_PCIIOBR_MASK;
        pr_debug("PCI: Setting upper bits of IO window to 0x%x\n", word);
-       pci_write_reg(word, SH4_PCIIOBR);
+       pci_write_reg(chan, word, SH4_PCIIOBR);
 
        /* Set PCI WCRx, BCRx's, copy from BSC locations */
 
        /* check BCR for SDRAM in specified area */
-       switch (map->window0.base) {
-       case SH7751_CS0_BASE_ADDR: word = __area_sdram_check(0); break;
-       case SH7751_CS1_BASE_ADDR: word = __area_sdram_check(1); break;
-       case SH7751_CS2_BASE_ADDR: word = __area_sdram_check(2); break;
-       case SH7751_CS3_BASE_ADDR: word = __area_sdram_check(3); break;
-       case SH7751_CS4_BASE_ADDR: word = __area_sdram_check(4); break;
-       case SH7751_CS5_BASE_ADDR: word = __area_sdram_check(5); break;
-       case SH7751_CS6_BASE_ADDR: word = __area_sdram_check(6); break;
+       switch (sh7751_pci_map.window0.base) {
+       case SH7751_CS0_BASE_ADDR: word = __area_sdram_check(chan, 0); break;
+       case SH7751_CS1_BASE_ADDR: word = __area_sdram_check(chan, 1); break;
+       case SH7751_CS2_BASE_ADDR: word = __area_sdram_check(chan, 2); break;
+       case SH7751_CS3_BASE_ADDR: word = __area_sdram_check(chan, 3); break;
+       case SH7751_CS4_BASE_ADDR: word = __area_sdram_check(chan, 4); break;
+       case SH7751_CS5_BASE_ADDR: word = __area_sdram_check(chan, 5); break;
+       case SH7751_CS6_BASE_ADDR: word = __area_sdram_check(chan, 6); break;
        }
 
        if (!word)
-               return 0;
+               return -1;
 
        /* configure the wait control registers */
        word = ctrl_inl(SH7751_WCR1);
-       pci_write_reg(word, SH4_PCIWCR1);
+       pci_write_reg(chan, word, SH4_PCIWCR1);
        word = ctrl_inl(SH7751_WCR2);
-       pci_write_reg(word, SH4_PCIWCR2);
+       pci_write_reg(chan, word, SH4_PCIWCR2);
        word = ctrl_inl(SH7751_WCR3);
-       pci_write_reg(word, SH4_PCIWCR3);
+       pci_write_reg(chan, word, SH4_PCIWCR3);
        word = ctrl_inl(SH7751_MCR);
-       pci_write_reg(word, SH4_PCIMCR);
+       pci_write_reg(chan, word, SH4_PCIMCR);
 
        /* NOTE: I'm ignoring the PCI error IRQs for now..
         * TODO: add support for the internal error interrupts and
         * DMA interrupts...
         */
 
-       pci_fixup_pcic();
+       pci_fixup_pcic(chan);
 
        /* SH7751 init done, set central function init complete */
        /* use round robin mode to stop a device starving/overruning */
        word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_ARBM;
-       pci_write_reg(word, SH4_PCICR);
+       pci_write_reg(chan, word, SH4_PCICR);
 
-       return 1;
+       register_pci_controller(chan);
+
+       return 0;
 }
+arch_initcall(sh7751_pci_init);
index 68e3cb5e6bec2f5c7804c4b7cb3cff60235ae534..4983a4d2035593daefb9ea6da47854f856e20374 100644 (file)
@@ -26,7 +26,6 @@
 #define SH7751_PCI_IO_SIZE           0x40000     /* Size of IO window */
 
 #define SH7751_PCIREG_BASE           0xFE200000  /* PCI regs base address */
-#define PCI_REG(n)                  (SH7751_PCIREG_BASE+ n)
 
 #define SH7751_PCICONF0            0x0           /* PCI Config Reg 0 */
   #define SH7751_PCICONF0_DEVID      0xFFFF0000  /* Device ID */
@@ -58,7 +57,7 @@
   #define SH7751_PCICONF2_SCC        0x00FF0000  /* Sub-Class Code */
   #define SH7751_PCICONF2_RLPI       0x0000FF00  /* Programming Interface */
   #define SH7751_PCICONF2_REV        0x000000FF  /* Revision ID */
-#define SH7751_PCICONF3            0xC           /* PCI Config Reg 3 */ 
+#define SH7751_PCICONF3            0xC           /* PCI Config Reg 3 */
   #define SH7751_PCICONF3_BIST7      0x80000000  /* Bist Supported */
   #define SH7751_PCICONF3_BIST6      0x40000000  /* Bist Executing */
   #define SH7751_PCICONF3_BIST3_0    0x0F000000  /* Bist Passed */
   #define SH7751_PCICONF5_BASE       0xFFFFFFF0  /* Mem Space Base Addr */
   #define SH7751_PCICONF5_LAP        0x00000008  /* Prefetch Enabled */
   #define SH7751_PCICONF5_LAT        0x00000006  /* Local Memory type */
-  #define SH7751_PCICONF5_ASI        0x00000001  /* Address Space Type */  
+  #define SH7751_PCICONF5_ASI        0x00000001  /* Address Space Type */
 #define SH7751_PCICONF6            0x18          /* PCI Config Reg 6 */
   #define SH7751_PCICONF6_BASE       0xFFFFFFF0  /* Mem Space Base Addr */
   #define SH7751_PCICONF6_LAP        0x00000008  /* Prefetch Enabled */
   #define SH7751_PCICONF6_LAT        0x00000006  /* Local Memory type */
-  #define SH7751_PCICONF6_ASI        0x00000001  /* Address Space Type */  
+  #define SH7751_PCICONF6_ASI        0x00000001  /* Address Space Type */
 /* PCICONF7 - PCICONF10 are undefined */
 #define SH7751_PCICONF11           0x2C          /* PCI Config Reg 11 */
   #define SH7751_PCICONF11_SSID      0xFFFF0000  /* Subsystem ID */
 #define SH7751_CS5_BASE_ADDR       (SH7751_CS4_BASE_ADDR + SH7751_MEM_REGION_SIZE)
 #define SH7751_CS6_BASE_ADDR       (SH7751_CS5_BASE_ADDR + SH7751_MEM_REGION_SIZE)
 
-struct sh4_pci_address_map;
-
-/* arch/sh/drivers/pci/pci-sh7751.c */
-int sh7751_pcic_init(struct sh4_pci_address_map *map);
-
 #endif /* _PCI_SH7751_H_ */
index bae6a2cf047dc0aace922c908a5a792a2322b82a..323b92d565fee57f2725bcd54b5758723535e458 100644 (file)
@@ -1,19 +1,12 @@
 /*
- *     Low-Level PCI Support for the SH7780
+ * Low-Level PCI Support for the SH7780
  *
- *  Dustin McIntire (dustin@sensoria.com)
- *     Derived from arch/i386/kernel/pci-*.c which bore the message:
- *     (c) 1999--2000 Martin Mares <mj@ucw.cz>
- *
- *  Ported to the new API by Paul Mundt <lethal@linux-sh.org>
- *  With cleanup by Paul van Gool <pvangool@mimotech.com>
- *
- *  May be copied or modified under the terms of the GNU General Public
- *  License.  See linux/COPYING for more information.
+ *  Copyright (C) 2005 - 2009  Paul Mundt
  *
+ * 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.
  */
-#undef DEBUG
-
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include "pci-sh4.h"
 
-#define INTC_BASE      0xffd00000
-#define INTC_ICR0      (INTC_BASE+0x0)
-#define INTC_ICR1      (INTC_BASE+0x1c)
-#define INTC_INTPRI    (INTC_BASE+0x10)
-#define INTC_INTREQ    (INTC_BASE+0x24)
-#define INTC_INTMSK0   (INTC_BASE+0x44)
-#define INTC_INTMSK1   (INTC_BASE+0x48)
-#define INTC_INTMSK2   (INTC_BASE+0x40080)
-#define INTC_INTMSKCLR0        (INTC_BASE+0x64)
-#define INTC_INTMSKCLR1        (INTC_BASE+0x68)
-#define INTC_INTMSKCLR2        (INTC_BASE+0x40084)
-#define INTC_INT2MSKR  (INTC_BASE+0x40038)
-#define INTC_INT2MSKCR (INTC_BASE+0x4003c)
+static struct resource sh7785_io_resource = {
+       .name   = "SH7785_IO",
+       .start  = SH7780_PCI_IO_BASE,
+       .end    = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1,
+       .flags  = IORESOURCE_IO
+};
+
+static struct resource sh7785_mem_resource = {
+       .name   = "SH7785_mem",
+       .start  = SH7780_PCI_MEMORY_BASE,
+       .end    = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
+       .flags  = IORESOURCE_MEM
+};
+
+static struct pci_channel sh7780_pci_controller = {
+       .pci_ops        = &sh4_pci_ops,
+       .mem_resource   = &sh7785_mem_resource,
+       .mem_offset     = 0x00000000,
+       .io_resource    = &sh7785_io_resource,
+       .io_offset      = 0x00000000,
+       .io_map_base    = SH7780_PCI_IO_BASE,
+};
+
+static struct sh4_pci_address_map sh7780_pci_map = {
+       .window0        = {
+#if defined(CONFIG_32BIT)
+               .base   = SH7780_32BIT_DDR_BASE_ADDR,
+               .size   = 0x40000000,
+#else
+               .base   = SH7780_CS0_BASE_ADDR,
+               .size   = 0x20000000,
+#endif
+       },
+};
 
-/*
- * Initialization. Try all known PCI access methods. Note that we support
- * using both PCI BIOS and direct access: in such cases, we use I/O ports
- * to access config space.
- *
- * Note that the platform specific initialization (BSC registers, and memory
- * space mapping) will be called via the platform defined function
- * pcibios_init_platform().
- */
 static int __init sh7780_pci_init(void)
 {
+       struct pci_channel *chan = &sh7780_pci_controller;
        unsigned int id;
-       int ret, match = 0;
-
-       pr_debug("PCI: Starting intialization.\n");
-
-       ctrl_outl(0x00000001, SH7780_PCI_VCR2); /* Enable PCIC */
-
-       /* check for SH7780/SH7780R hardware */
-       id = pci_read_reg(SH7780_PCIVID);
-       if ((id & 0xffff) == SH7780_VENDOR_ID) {
-               switch ((id >> 16) & 0xffff) {
-               case SH7763_DEVICE_ID:
-               case SH7780_DEVICE_ID:
-               case SH7781_DEVICE_ID:
-               case SH7785_DEVICE_ID:
-                       match = 1;
-                       break;
-               }
-       }
+       const char *type = NULL;
+       int ret;
+       u32 word;
 
-       if (unlikely(!match)) {
-               printk(KERN_ERR "PCI: This is not an SH7780 (%x)\n", id);
+       printk(KERN_NOTICE "PCI: Starting intialization.\n");
+
+       chan->reg_base = 0xfe040000;
+
+       /* Enable CPU access to the PCIC registers. */
+       __raw_writel(PCIECR_ENBL, PCIECR);
+
+       id = __raw_readw(chan->reg_base + SH7780_PCIVID);
+       if (id != SH7780_VENDOR_ID) {
+               printk(KERN_ERR "PCI: Unknown vendor ID 0x%04x.\n", id);
                return -ENODEV;
        }
 
-       /* Setup the INTC */
-       if (mach_is_7780se()) {
-               /* ICR0: IRL=use separately */
-               ctrl_outl(0x00C00020, INTC_ICR0);
-               /* ICR1: detect low level(for 2ndcut) */
-               ctrl_outl(0xAAAA0000, INTC_ICR1);
-               /* INTPRI: priority=3(all) */
-               ctrl_outl(0x33333333, INTC_INTPRI);
+       id = __raw_readw(chan->reg_base + SH7780_PCIDID);
+       type = (id == SH7763_DEVICE_ID) ? "SH7763" :
+              (id == SH7780_DEVICE_ID) ? "SH7780" :
+              (id == SH7781_DEVICE_ID) ? "SH7781" :
+              (id == SH7785_DEVICE_ID) ? "SH7785" :
+                                         NULL;
+       if (unlikely(!type)) {
+               printk(KERN_ERR "PCI: Found an unsupported Renesas host "
+                      "controller, device id 0x%04x.\n", id);
+               return -EINVAL;
        }
 
-       if ((ret = sh4_pci_check_direct()) != 0)
-               return ret;
+       printk(KERN_NOTICE "PCI: Found a Renesas %s host "
+              "controller, revision %d.\n", type,
+              __raw_readb(chan->reg_base + SH7780_PCIRID));
 
-       return pcibios_init_platform();
-}
-core_initcall(sh7780_pci_init);
-
-int __init sh7780_pcic_init(struct sh4_pci_address_map *map)
-{
-       u32 word;
+       if ((ret = sh4_pci_check_direct(chan)) != 0)
+               return ret;
 
        /*
-        * This code is unused for some boards as it is done in the
-        * bootloader and doing it here means the MAC addresses loaded
-        * by the bootloader get lost.
-        */
-       if (!(map->flags & SH4_PCIC_NO_RESET)) {
-               /* toggle PCI reset pin */
-               word = SH4_PCICR_PREFIX | SH4_PCICR_PRST;
-               pci_write_reg(word, SH4_PCICR);
-               /* Wait for a long time... not 1 sec. but long enough */
-               mdelay(100);
-               word = SH4_PCICR_PREFIX;
-               pci_write_reg(word, SH4_PCICR);
-       }
-
-       /* set the command/status bits to:
-        * Wait Cycle Control + Parity Enable + Bus Master +
-        * Mem space enable
+        * Set the class and sub-class codes.
         */
-       pci_write_reg(0x00000046, SH7780_PCICMD);
-
-       /* define this host as the host bridge */
-       word = PCI_BASE_CLASS_BRIDGE << 24;
-       pci_write_reg(word, SH7780_PCIRID);
+       __raw_writeb(PCI_CLASS_BRIDGE_HOST >> 8,
+                    chan->reg_base + SH7780_PCIBCC);
+       __raw_writeb(PCI_CLASS_BRIDGE_HOST & 0xff,
+                    chan->reg_base + SH7780_PCISUB);
 
-       /* Set IO and Mem windows to local address
+       /*
+        * Set IO and Mem windows to local address
         * Make PCI and local address the same for easy 1 to 1 mapping
         */
-       pci_write_reg(map->window0.size - 0xfffff, SH4_PCILSR0);
-       pci_write_reg(map->window1.size - 0xfffff, SH4_PCILSR1);
+       pci_write_reg(chan, sh7780_pci_map.window0.size - 0xfffff, SH4_PCILSR0);
        /* Set the values on window 0 PCI config registers */
-       pci_write_reg(map->window0.base, SH4_PCILAR0);
-       pci_write_reg(map->window0.base, SH7780_PCIMBAR0);
-       /* Set the values on window 1 PCI config registers */
-       pci_write_reg(map->window1.base, SH4_PCILAR1);
-       pci_write_reg(map->window1.base, SH7780_PCIMBAR1);
-
-       /* Map IO space into PCI IO window
-        * The IO window is 64K-PCIBIOS_MIN_IO in size
-        * IO addresses will be translated to the
-        * PCI IO window base address
-        */
-       pr_debug("PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n",
-                PCIBIOS_MIN_IO, (64 << 10),
-                SH7780_PCI_IO_BASE + PCIBIOS_MIN_IO);
+       pci_write_reg(chan, sh7780_pci_map.window0.base, SH4_PCILAR0);
+       pci_write_reg(chan, sh7780_pci_map.window0.base, SH7780_PCIMBAR0);
 
-       /* NOTE: I'm ignoring the PCI error IRQs for now..
-        * TODO: add support for the internal error interrupts and
-        * DMA interrupts...
-        */
+       pci_write_reg(chan, 0x0000380f, SH4_PCIAINTM);
+
+       /* Set up standard PCI config registers */
+       __raw_writew(0xFB00, chan->reg_base + SH7780_PCISTATUS);
+       __raw_writew(0x0047, chan->reg_base + SH7780_PCICMD);
+       __raw_writew(0x1912, chan->reg_base + SH7780_PCISVID);
+       __raw_writew(0x0001, chan->reg_base + SH7780_PCISID);
+
+       __raw_writeb(0x00, chan->reg_base + SH7780_PCIPIF);
 
        /* Apply any last-minute PCIC fixups */
-       pci_fixup_pcic();
+       pci_fixup_pcic(chan);
+
+       pci_write_reg(chan, 0xfd000000, SH7780_PCIMBR0);
+       pci_write_reg(chan, 0x00fc0000, SH7780_PCIMBMR0);
+
+#ifdef CONFIG_32BIT
+       pci_write_reg(chan, 0xc0000000, SH7780_PCIMBR2);
+       pci_write_reg(chan, 0x20000000 - SH7780_PCI_IO_SIZE, SH7780_PCIMBMR2);
+#endif
+
+       /* Set IOBR for windows containing area specified in pci.h */
+       pci_write_reg(chan, chan->io_resource->start & ~(SH7780_PCI_IO_SIZE-1),
+                     SH7780_PCIIOBR);
+       pci_write_reg(chan, ((SH7780_PCI_IO_SIZE-1) & (7<<18)),
+                     SH7780_PCIIOBMR);
 
        /* SH7780 init done, set central function init complete */
        /* use round robin mode to stop a device starving/overruning */
        word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO;
-       pci_write_reg(word, SH4_PCICR);
+       pci_write_reg(chan, word, SH4_PCICR);
+
+       register_pci_controller(chan);
 
-       return 1;
+       return 0;
 }
+arch_initcall(sh7780_pci_init);
index 93adc7119b790df7ae7dc92644a63dbaa22654b0..4a52478c97cf61e331748e8f3a9dd264ce09efe3 100644 (file)
@@ -20,9 +20,8 @@
 #define SH7785_DEVICE_ID       0x0007
 
 /* SH7780 Control Registers */
-#define        SH7780_PCI_VCR0         0xFE000000
-#define        SH7780_PCI_VCR1         0xFE000004
-#define        SH7780_PCI_VCR2         0xFE000008
+#define        PCIECR                  0xFE000008
+#define PCIECR_ENBL            0x01
 
 /* SH7780 Specific Values */
 #define SH7780_PCI_CONFIG_BASE 0xFD000000      /* Config space base addr */
@@ -35,7 +34,6 @@
 #define SH7780_PCI_IO_SIZE     0x00400000      /* Size of IO window */
 
 #define SH7780_PCIREG_BASE     0xFE040000      /* PCI regs base address */
-#define PCI_REG(n)             (SH7780_PCIREG_BASE+n)
 
 /* SH7780 PCI Config Registers */
 #define SH7780_PCIVID          0x000           /* Vendor ID */
 #define SH7780_PCIPMCSR_BSE    0x046
 #define SH7780_PCICDD          0x047
 
-#define SH7780_PCICR           0x100           /* PCI Control Register */
-#define SH7780_PCILSR          0x104           /* PCI Local Space Register0 */
-#define SH7780_PCILSR1         0x108           /* PCI Local Space Register1 */
-#define SH7780_PCILAR0         0x10C           /* PCI Local Address Register1 */
-#define SH7780_PCILAR1         0x110           /* PCI Local Address Register1 */
 #define SH7780_PCIIR           0x114           /* PCI Interrupt Register */
 #define SH7780_PCIIMR          0x118           /* PCI Interrupt Mask Register */
 #define SH7780_PCIAIR          0x11C           /* Error Address Register */
 
 #define SH7780_32BIT_DDR_BASE_ADDR     0x40000000
 
-struct sh4_pci_address_map;
-
-/* arch/sh/drivers/pci/pci-sh7780.c */
-int sh7780_pcic_init(struct sh4_pci_address_map *map);
-
 #endif /* _PCI_SH7780_H_ */
index 0d6ac7a1db4987f55bbd874bae48fb96359fe314..54d77cbb8b39e62fa718191f1275df5b40ab8b56 100644 (file)
 /*
- * arch/sh/drivers/pci/pci.c
+ * New-style PCI core.
  *
- * Copyright (c) 2002 M. R. Brown  <mrbrown@linux-sh.org>
- * Copyright (c) 2004 - 2006 Paul Mundt  <lethal@linux-sh.org>
+ * Copyright (c) 2004 - 2009  Paul Mundt
+ * Copyright (c) 2002  M. R. Brown
  *
- * These functions are collected here to reduce duplication of common
- * code amongst the many platform-specific PCI support code files.
- *
- * These routines require the following board-specific routines:
- * void pcibios_fixup_irqs();
- *
- * See include/asm-sh/pci.h for more information.
+ * Modelled after arch/mips/pci/pci.c:
+ *  Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org)
  *
  * 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.
  */
 #include <linux/kernel.h>
+#include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/types.h>
 #include <linux/dma-debug.h>
-#include <asm/io.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
 
-static int __init pcibios_init(void)
+unsigned long PCIBIOS_MIN_IO = 0x0000;
+unsigned long PCIBIOS_MIN_MEM = 0;
+
+/*
+ * The PCI controller list.
+ */
+static struct pci_channel *hose_head, **hose_tail = &hose_head;
+
+static int pci_initialized;
+
+static void __devinit pcibios_scanbus(struct pci_channel *hose)
 {
-       struct pci_channel *p;
+       static int next_busno;
        struct pci_bus *bus;
-       int busno;
 
-#ifdef CONFIG_PCI_AUTO
-       /* assign resources */
-       busno = 0;
-       for (p = board_pci_channels; p->pci_ops != NULL; p++)
-               busno = pciauto_assign_resources(busno, p) + 1;
-#endif
+       bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
+       if (bus) {
+               next_busno = bus->subordinate + 1;
+               /* Don't allow 8-bit bus number overflow inside the hose -
+                  reserve some space for bridges. */
+               if (next_busno > 224)
+                       next_busno = 0;
+
+               pci_bus_size_bridges(bus);
+               pci_bus_assign_resources(bus);
+               pci_enable_bridges(bus);
+       }
+}
+
+static DEFINE_MUTEX(pci_scan_mutex);
 
-       /* scan the buses */
-       busno = 0;
-       for (p = board_pci_channels; p->pci_ops != NULL; p++) {
-               bus = pci_scan_bus(busno, p->pci_ops, p);
-               busno = bus->subordinate + 1;
+void __devinit register_pci_controller(struct pci_channel *hose)
+{
+       if (request_resource(&iomem_resource, hose->mem_resource) < 0)
+               goto out;
+       if (request_resource(&ioport_resource, hose->io_resource) < 0) {
+               release_resource(hose->mem_resource);
+               goto out;
        }
 
+       *hose_tail = hose;
+       hose_tail = &hose->next;
+
+       /*
+        * Do not panic here but later - this might hapen before console init.
+        */
+       if (!hose->io_map_base) {
+               printk(KERN_WARNING
+                      "registering PCI controller with io_map_base unset\n");
+       }
+
+       /*
+        * Scan the bus if it is register after the PCI subsystem
+        * initialization.
+        */
+       if (pci_initialized) {
+               mutex_lock(&pci_scan_mutex);
+               pcibios_scanbus(hose);
+               mutex_unlock(&pci_scan_mutex);
+       }
+
+       return;
+
+out:
+       printk(KERN_WARNING
+              "Skipping PCI bus scan due to resource conflict\n");
+}
+
+static int __init pcibios_init(void)
+{
+       struct pci_channel *hose;
+
+       /* Scan all of the recorded PCI controllers.  */
+       for (hose = hose_head; hose; hose = hose->next)
+               pcibios_scanbus(hose);
+
        pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
 
        dma_debug_add_bus(&pci_bus_type);
 
+       pci_initialized = 1;
+
        return 0;
 }
 subsys_initcall(pcibios_init);
 
+static void pcibios_fixup_device_resources(struct pci_dev *dev,
+       struct pci_bus *bus)
+{
+       /* Update device resources.  */
+       struct pci_channel *hose = bus->sysdata;
+       unsigned long offset = 0;
+       int i;
+
+       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+               if (!dev->resource[i].start)
+                       continue;
+               if (dev->resource[i].flags & IORESOURCE_PCI_FIXED)
+                       continue;
+               if (dev->resource[i].flags & IORESOURCE_IO)
+                       offset = hose->io_offset;
+               else if (dev->resource[i].flags & IORESOURCE_MEM)
+                       offset = hose->mem_offset;
+
+               dev->resource[i].start += offset;
+               dev->resource[i].end += offset;
+       }
+}
+
 /*
  *  Called after each bus is probed, but before its children
  *  are examined.
  */
-void __devinit __weak pcibios_fixup_bus(struct pci_bus *bus)
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
-       pci_read_bridge_bases(bus);
-}
+       struct pci_dev *dev = bus->self;
+       struct list_head *ln;
+       struct pci_channel *chan = bus->sysdata;
 
-void pcibios_align_resource(void *data, struct resource *res,
-                           resource_size_t size, resource_size_t align)
-                           __attribute__ ((weak));
+       if (!dev) {
+               bus->resource[0] = chan->io_resource;
+               bus->resource[1] = chan->mem_resource;
+       }
+
+       for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
+               dev = pci_dev_b(ln);
+
+               if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+                       pcibios_fixup_device_resources(dev, bus);
+       }
+}
 
 /*
  * We need to avoid collisions with `mirrored' VGA ports
@@ -72,14 +161,58 @@ void pcibios_align_resource(void *data, struct resource *res,
 void pcibios_align_resource(void *data, struct resource *res,
                            resource_size_t size, resource_size_t align)
 {
+       struct pci_dev *dev = data;
+       struct pci_channel *chan = dev->sysdata;
+       resource_size_t start = res->start;
+
        if (res->flags & IORESOURCE_IO) {
-               resource_size_t start = res->start;
+               if (start < PCIBIOS_MIN_IO + chan->io_resource->start)
+                       start = PCIBIOS_MIN_IO + chan->io_resource->start;
 
+               /*
+                 * Put everything into 0x00-0xff region modulo 0x400.
+                */
                if (start & 0x300) {
                        start = (start + 0x3ff) & ~0x3ff;
                        res->start = start;
                }
+       } else if (res->flags & IORESOURCE_MEM) {
+               if (start < PCIBIOS_MIN_MEM + chan->mem_resource->start)
+                       start = PCIBIOS_MIN_MEM + chan->mem_resource->start;
        }
+
+       res->start = start;
+}
+
+void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+                        struct resource *res)
+{
+       struct pci_channel *hose = dev->sysdata;
+       unsigned long offset = 0;
+
+       if (res->flags & IORESOURCE_IO)
+               offset = hose->io_offset;
+       else if (res->flags & IORESOURCE_MEM)
+               offset = hose->mem_offset;
+
+       region->start = res->start - offset;
+       region->end = res->end - offset;
+}
+
+void __devinit
+pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+                       struct pci_bus_region *region)
+{
+       struct pci_channel *hose = dev->sysdata;
+       unsigned long offset = 0;
+
+       if (res->flags & IORESOURCE_IO)
+               offset = hose->io_offset;
+       else if (res->flags & IORESOURCE_MEM)
+               offset = hose->mem_offset;
+
+       res->start = region->start + offset;
+       res->end = region->end + offset;
 }
 
 int pcibios_enable_device(struct pci_dev *dev, int mask)
@@ -90,13 +223,21 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
 
        pci_read_config_word(dev, PCI_COMMAND, &cmd);
        old_cmd = cmd;
-       for(idx=0; idx<6; idx++) {
-               if (!(mask & (1 << idx)))
+       for (idx=0; idx < PCI_NUM_RESOURCES; idx++) {
+               /* Only set up the requested stuff */
+               if (!(mask & (1<<idx)))
                        continue;
+
                r = &dev->resource[idx];
+               if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
+                       continue;
+               if ((idx == PCI_ROM_RESOURCE) &&
+                               (!(r->flags & IORESOURCE_ROM_ENABLE)))
+                       continue;
                if (!r->start && r->end) {
-                       printk(KERN_ERR "PCI: Device %s not available because "
-                              "of resource collisions\n", pci_name(dev));
+                       printk(KERN_ERR "PCI: Device %s not available "
+                              "because of resource collisions\n",
+                              pci_name(dev));
                        return -EINVAL;
                }
                if (r->flags & IORESOURCE_IO)
@@ -104,10 +245,8 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
                if (r->flags & IORESOURCE_MEM)
                        cmd |= PCI_COMMAND_MEMORY;
        }
-       if (dev->resource[PCI_ROM_RESOURCE].start)
-               cmd |= PCI_COMMAND_MEMORY;
        if (cmd != old_cmd) {
-               printk(KERN_INFO "PCI: Enabling device %s (%04x -> %04x)\n",
+               printk("PCI: Enabling device %s (%04x -> %04x)\n",
                       pci_name(dev), old_cmd, cmd);
                pci_write_config_word(dev, PCI_COMMAND, cmd);
        }
@@ -140,6 +279,43 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
+char * __devinit pcibios_setup(char *str)
+{
+       return str;
+}
+
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+                       enum pci_mmap_state mmap_state, int write_combine)
+{
+       /*
+        * I/O space can be accessed via normal processor loads and stores on
+        * this platform but for now we elect not to do this and portable
+        * drivers should not do this anyway.
+        */
+       if (mmap_state == pci_mmap_io)
+               return -EINVAL;
+
+       /*
+        * Ignore write-combine; for now only return uncached mappings.
+        */
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+                              vma->vm_end - vma->vm_start,
+                              vma->vm_page_prot);
+}
+
+static void __iomem *ioport_map_pci(struct pci_dev *dev,
+                                   unsigned long port, unsigned int nr)
+{
+       struct pci_channel *chan = dev->sysdata;
+
+       if (!chan->io_map_base)
+               chan->io_map_base = generic_io_base;
+
+       return (void __iomem *)(chan->io_map_base + port);
+}
+
 void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
 {
        resource_size_t start = pci_resource_start(dev, bar);
@@ -151,20 +327,24 @@ void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
        if (maxlen && len > maxlen)
                len = maxlen;
 
+       if (flags & IORESOURCE_IO)
+               return ioport_map_pci(dev, start, len);
+
        /*
         * Presently the IORESOURCE_MEM case is a bit special, most
         * SH7751 style PCI controllers have PCI memory at a fixed
-        * location in the address space where no remapping is desired
-        * (typically at 0xfd000000, but is_pci_memaddr() will know
-        * best). With the IORESOURCE_MEM case more care has to be taken
+        * location in the address space where no remapping is desired.
+        * With the IORESOURCE_MEM case more care has to be taken
         * to inhibit page table mapping for legacy cores, but this is
         * punted off to __ioremap().
         *                                      -- PFM.
         */
-       if (flags & IORESOURCE_IO)
-               return ioport_map(start, len);
-       if (flags & IORESOURCE_MEM)
-               return ioremap(start, len);
+       if (flags & IORESOURCE_MEM) {
+               if (flags & IORESOURCE_CACHEABLE)
+                       return ioremap(start, len);
+
+               return ioremap_nocache(start, len);
+       }
 
        return NULL;
 }
@@ -175,3 +355,10 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
        iounmap(addr);
 }
 EXPORT_SYMBOL(pci_iounmap);
+
+#ifdef CONFIG_HOTPLUG
+EXPORT_SYMBOL(pcibios_resource_to_bus);
+EXPORT_SYMBOL(pcibios_bus_to_resource);
+EXPORT_SYMBOL(PCIBIOS_MIN_IO);
+EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
+#endif
index 4b00b78e3f4f3a6a5be4a70a924123c84f32c895..b040e1e086108c606c6da8ecbd712b0dca2b1734 100644 (file)
@@ -104,4 +104,31 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
        : "t");
 }
 
+#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+       int c, old;
+       c = atomic_read(v);
+       for (;;) {
+               if (unlikely(c == (u)))
+                       break;
+               old = atomic_cmpxchg((v), c, c + (a));
+               if (likely(old == c))
+                       break;
+               c = old;
+       }
+
+       return c != (u);
+}
+
 #endif /* __ASM_SH_ATOMIC_LLSC_H */
index 6327ffbb19928e51305a2d472cbdcd31863a0823..978b58efb1e92e18464010bfeeeae5a5296de3c0 100644 (file)
@@ -45,7 +45,7 @@
 #define atomic_inc(v) atomic_add(1,(v))
 #define atomic_dec(v) atomic_sub(1,(v))
 
-#ifndef CONFIG_GUSA_RB
+#if !defined(CONFIG_GUSA_RB) && !defined(CONFIG_CPU_SH4A)
 static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
 {
        int ret;
@@ -73,7 +73,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 
        return ret != u;
 }
-#endif
+#endif /* !CONFIG_GUSA_RB && !CONFIG_CPU_SH4A */
 
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
index 09acbc32d6c7effc6adfd7e7ad9bae2551b251a5..4c5462daa74cffaad2f14b05c1e1f58e54097d72 100644 (file)
@@ -75,7 +75,5 @@ extern void copy_from_user_page(struct vm_area_struct *vma,
 #define flush_cache_vmap(start, end)           flush_cache_all()
 #define flush_cache_vunmap(start, end)         flush_cache_all()
 
-#define HAVE_ARCH_UNMAPPED_AREA
-
 #endif /* __KERNEL__ */
 #endif /* __ASM_SH_CACHEFLUSH_H */
index 2f6c9627bc1f81c6dcbc041ee003b47010ae8f21..9fe7d7f8af404646dfcce651d53727f69fc91653 100644 (file)
@@ -1,9 +1,9 @@
 #ifndef __ASM_SH_CLOCK_H
 #define __ASM_SH_CLOCK_H
 
-#include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/seq_file.h>
+#include <linux/cpufreq.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 
@@ -11,9 +11,9 @@ struct clk;
 
 struct clk_ops {
        void (*init)(struct clk *clk);
-       void (*enable)(struct clk *clk);
+       int (*enable)(struct clk *clk);
        void (*disable)(struct clk *clk);
-       void (*recalc)(struct clk *clk);
+       unsigned long (*recalc)(struct clk *clk);
        int (*set_rate)(struct clk *clk, unsigned long rate, int algo_id);
        int (*set_parent)(struct clk *clk, struct clk *parent);
        long (*round_rate)(struct clk *clk, unsigned long rate);
@@ -28,43 +28,47 @@ struct clk {
        struct clk              *parent;
        struct clk_ops          *ops;
 
-       struct kref             kref;
+       struct list_head        children;
+       struct list_head        sibling;        /* node for children */
+
+       int                     usecount;
 
        unsigned long           rate;
        unsigned long           flags;
+
+       void __iomem            *enable_reg;
+       unsigned int            enable_bit;
+
        unsigned long           arch_flags;
+       void                    *priv;
+       struct dentry           *dentry;
+       struct cpufreq_frequency_table *freq_table;
+};
+
+struct clk_lookup {
+       struct list_head        node;
+       const char              *dev_id;
+       const char              *con_id;
+       struct clk              *clk;
 };
 
-#define CLK_ALWAYS_ENABLED     (1 << 0)
-#define CLK_RATE_PROPAGATES    (1 << 1)
+#define CLK_ENABLE_ON_INIT     (1 << 0)
 
 /* Should be defined by processor-specific code */
-void arch_init_clk_ops(struct clk_ops **, int type);
+void __deprecated arch_init_clk_ops(struct clk_ops **, int type);
 int __init arch_clk_init(void);
 
 /* arch/sh/kernel/cpu/clock.c */
 int clk_init(void);
-
-void clk_recalc_rate(struct clk *);
-
+unsigned long followparent_recalc(struct clk *);
+void recalculate_root_clocks(void);
+void propagate_rate(struct clk *);
+int clk_reparent(struct clk *child, struct clk *parent);
 int clk_register(struct clk *);
 void clk_unregister(struct clk *);
 
-static inline int clk_always_enable(const char *id)
-{
-       struct clk *clk;
-       int ret;
-
-       clk = clk_get(NULL, id);
-       if (IS_ERR(clk))
-               return PTR_ERR(clk);
-
-       ret = clk_enable(clk);
-       if (ret)
-               clk_put(clk);
-
-       return ret;
-}
+/* arch/sh/kernel/cpu/clock-cpg.c */
+int __init __deprecated cpg_clk_init(void);
 
 /* the exported API, in addition to clk_set_rate */
 /**
@@ -96,4 +100,63 @@ enum clk_sh_algo_id {
 
        IP_N1,
 };
+
+struct clk_div_mult_table {
+       unsigned int *divisors;
+       unsigned int nr_divisors;
+       unsigned int *multipliers;
+       unsigned int nr_multipliers;
+};
+
+struct cpufreq_frequency_table;
+void clk_rate_table_build(struct clk *clk,
+                         struct cpufreq_frequency_table *freq_table,
+                         int nr_freqs,
+                         struct clk_div_mult_table *src_table,
+                         unsigned long *bitmap);
+
+long clk_rate_table_round(struct clk *clk,
+                         struct cpufreq_frequency_table *freq_table,
+                         unsigned long rate);
+
+int clk_rate_table_find(struct clk *clk,
+                       struct cpufreq_frequency_table *freq_table,
+                       unsigned long rate);
+
+#define SH_CLK_MSTP32(_name, _id, _parent, _enable_reg,        \
+           _enable_bit, _flags)                        \
+{                                                      \
+       .name           = _name,                        \
+       .id             = _id,                          \
+       .parent         = _parent,                      \
+       .enable_reg     = (void __iomem *)_enable_reg,  \
+       .enable_bit     = _enable_bit,                  \
+       .flags          = _flags,                       \
+}
+
+int sh_clk_mstp32_register(struct clk *clks, int nr);
+
+#define SH_CLK_DIV4(_name, _parent, _reg, _shift, _div_bitmap, _flags) \
+{                                                                      \
+       .name = _name,                                                  \
+       .parent = _parent,                                              \
+       .enable_reg = (void __iomem *)_reg,                             \
+       .enable_bit = _shift,                                           \
+       .arch_flags = _div_bitmap,                                      \
+       .flags = _flags,                                                \
+}
+
+int sh_clk_div4_register(struct clk *clks, int nr,
+                        struct clk_div_mult_table *table);
+
+#define SH_CLK_DIV6(_name, _parent, _reg, _flags)      \
+{                                                      \
+       .name = _name,                                  \
+       .parent = _parent,                              \
+       .enable_reg = (void __iomem *)_reg,             \
+       .flags = _flags,                                \
+}
+
+int sh_clk_div6_register(struct clk *clks, int nr);
+
 #endif /* __ASM_SH_CLOCK_H */
index 0fac3da536ca025797385130a9972296c578276c..47136661a203a96ad2c5d676fff377bf789cbafb 100644 (file)
@@ -55,7 +55,7 @@ __cmpxchg_u32(volatile int *m, unsigned long old, unsigned long new)
                "mov            %0, %1                          \n\t"
                "cmp/eq         %1, %3                          \n\t"
                "bf             2f                              \n\t"
-               "mov            %3, %0                          \n\t"
+               "mov            %4, %0                          \n\t"
                "2:                                             \n\t"
                "movco.l        %0, @%2                         \n\t"
                "bf             1b                              \n\t"
index efd511d0803ad4002fcb73f8a04af39aa51eede3..8688a88303ee79f3b422ca81f76d34287aa1a791 100644 (file)
@@ -10,3 +10,5 @@ struct platform_device;
 int platform_resource_setup_memory(struct platform_device *pdev,
                                   char *name, unsigned long memsize);
 
+void plat_early_device_setup(void);
+
index 52b4b62382777a3d03ff41c62441d0102521be61..977355f0a48365c34aa73cadb426321033bc4bf9 100644 (file)
 #define        HD64461_PCC_WINDOW      0x01000000
 
 /* Area 6 - Slot 0 - memory and/or IO card */
-#define        HD64461_PCC0_BASE       (CONFIG_HD64461_IOBASE + 0x8000000)
+#define HD64461_IOBASE         0xb0000000
+#define HD64461_IO_OFFSET(x)   (HD64461_IOBASE + (x))
+#define        HD64461_PCC0_BASE       HD64461_IO_OFFSET(0x8000000)
 #define        HD64461_PCC0_ATTR       (HD64461_PCC0_BASE)                             /* 0xb80000000 */
 #define        HD64461_PCC0_COMM       (HD64461_PCC0_BASE+HD64461_PCC_WINDOW)          /* 0xb90000000 */
 #define        HD64461_PCC0_IO         (HD64461_PCC0_BASE+2*HD64461_PCC_WINDOW)        /* 0xba0000000 */
 
 /* Area 5 - Slot 1 - memory card only */
-#define        HD64461_PCC1_BASE       (CONFIG_HD64461_IOBASE + 0x4000000)
+#define        HD64461_PCC1_BASE       HD64461_IO_OFFSET(0x4000000)
 #define        HD64461_PCC1_ATTR       (HD64461_PCC1_BASE)                             /* 0xb4000000 */
 #define        HD64461_PCC1_COMM       (HD64461_PCC1_BASE+HD64461_PCC_WINDOW)          /* 0xb5000000 */
 
 /* Standby Control Register for HD64461 */
-#define        HD64461_STBCR                   CONFIG_HD64461_IOBASE
+#define        HD64461_STBCR                   HD64461_IO_OFFSET(0x00000000)
 #define        HD64461_STBCR_CKIO_STBY         0x2000
 #define        HD64461_STBCR_SAFECKE_IST       0x1000
 #define        HD64461_STBCR_SLCKE_IST         0x0800
 #define        HD64461_STBCR_SURTST            0x0001
 
 /* System Configuration Register */
-#define        HD64461_SYSCR           (CONFIG_HD64461_IOBASE + 0x02)
+#define        HD64461_SYSCR           HD64461_IO_OFFSET(0x02)
 
 /* CPU Data Bus Control Register */
-#define        HD64461_SCPUCR          (CONFIG_HD64461_IOBASE + 0x04)
+#define        HD64461_SCPUCR          HD64461_IO_OFFSET(0x04)
 
 /* Base Address Register */
-#define        HD64461_LCDCBAR         (CONFIG_HD64461_IOBASE + 0x1000)
+#define        HD64461_LCDCBAR         HD64461_IO_OFFSET(0x1000)
 
 /* Line increment address */
-#define        HD64461_LCDCLOR         (CONFIG_HD64461_IOBASE + 0x1002)
+#define        HD64461_LCDCLOR         HD64461_IO_OFFSET(0x1002)
 
 /* Controls LCD controller */
-#define        HD64461_LCDCCR          (CONFIG_HD64461_IOBASE + 0x1004)
+#define        HD64461_LCDCCR          HD64461_IO_OFFSET(0x1004)
 
 /* LCCDR control bits */
 #define        HD64461_LCDCCR_STBACK   0x0400  /* Standby Back */
 #define        HD64461_LCDCCR_SPON     0x0010  /* Start Power On */
 
 /* Controls LCD (1) */
-#define        HD64461_LDR1            (CONFIG_HD64461_IOBASE + 0x1010)
+#define        HD64461_LDR1            HD64461_IO_OFFSET(0x1010)
 #define        HD64461_LDR1_DON        0x01    /* Display On */
 #define        HD64461_LDR1_DINV       0x80    /* Display Invert */
 
 /* Controls LCD (2) */
-#define        HD64461_LDR2            (CONFIG_HD64461_IOBASE + 0x1012)
-#define        HD64461_LDHNCR          (CONFIG_HD64461_IOBASE + 0x1014)        /* Number of horizontal characters */
-#define        HD64461_LDHNSR          (CONFIG_HD64461_IOBASE + 0x1016)        /* Specify output start position + width of CL1 */
-#define        HD64461_LDVNTR          (CONFIG_HD64461_IOBASE + 0x1018)        /* Specify total vertical lines */
-#define        HD64461_LDVNDR          (CONFIG_HD64461_IOBASE + 0x101a)        /* specify number of display vertical lines */
-#define        HD64461_LDVSPR          (CONFIG_HD64461_IOBASE + 0x101c)        /* specify vertical synchronization pos and AC nr */
+#define        HD64461_LDR2            HD64461_IO_OFFSET(0x1012)
+#define        HD64461_LDHNCR          HD64461_IO_OFFSET(0x1014)       /* Number of horizontal characters */
+#define        HD64461_LDHNSR          HD64461_IO_OFFSET(0x1016)       /* Specify output start position + width of CL1 */
+#define        HD64461_LDVNTR          HD64461_IO_OFFSET(0x1018)       /* Specify total vertical lines */
+#define        HD64461_LDVNDR          HD64461_IO_OFFSET(0x101a)       /* specify number of display vertical lines */
+#define        HD64461_LDVSPR          HD64461_IO_OFFSET(0x101c)       /* specify vertical synchronization pos and AC nr */
 
 /* Controls LCD (3) */
-#define        HD64461_LDR3            (CONFIG_HD64461_IOBASE + 0x101e)
+#define        HD64461_LDR3            HD64461_IO_OFFSET(0x101e)
 
 /* Palette Registers */
-#define        HD64461_CPTWAR          (CONFIG_HD64461_IOBASE + 0x1030)        /* Color Palette Write Address Register */
-#define        HD64461_CPTWDR          (CONFIG_HD64461_IOBASE + 0x1032)        /* Color Palette Write Data Register */
-#define        HD64461_CPTRAR          (CONFIG_HD64461_IOBASE + 0x1034)        /* Color Palette Read Address Register */
-#define        HD64461_CPTRDR          (CONFIG_HD64461_IOBASE + 0x1036)        /* Color Palette Read Data Register */
+#define        HD64461_CPTWAR          HD64461_IO_OFFSET(0x1030)       /* Color Palette Write Address Register */
+#define        HD64461_CPTWDR          HD64461_IO_OFFSET(0x1032)       /* Color Palette Write Data Register */
+#define        HD64461_CPTRAR          HD64461_IO_OFFSET(0x1034)       /* Color Palette Read Address Register */
+#define        HD64461_CPTRDR          HD64461_IO_OFFSET(0x1036)       /* Color Palette Read Data Register */
 
-#define        HD64461_GRDOR           (CONFIG_HD64461_IOBASE + 0x1040)        /* Display Resolution Offset Register */
-#define        HD64461_GRSCR           (CONFIG_HD64461_IOBASE + 0x1042)        /* Solid Color Register */
-#define        HD64461_GRCFGR          (CONFIG_HD64461_IOBASE + 0x1044)        /* Accelerator Configuration Register */
+#define        HD64461_GRDOR           HD64461_IO_OFFSET(0x1040)       /* Display Resolution Offset Register */
+#define        HD64461_GRSCR           HD64461_IO_OFFSET(0x1042)       /* Solid Color Register */
+#define        HD64461_GRCFGR          HD64461_IO_OFFSET(0x1044)       /* Accelerator Configuration Register */
 
 #define        HD64461_GRCFGR_ACCSTATUS        0x10    /* Accelerator Status */
 #define        HD64461_GRCFGR_ACCRESET         0x08    /* Accelerator Reset */
 #define        HD64461_GRCFGR_COLORDEPTH8      0x01    /* Sets Colordepth 8 for Accelerator */
 
 /* Line Drawing Registers */
-#define        HD64461_LNSARH          (CONFIG_HD64461_IOBASE + 0x1046)        /* Line Start Address Register (H) */
-#define        HD64461_LNSARL          (CONFIG_HD64461_IOBASE + 0x1048)        /* Line Start Address Register (L) */
-#define        HD64461_LNAXLR          (CONFIG_HD64461_IOBASE + 0x104a)        /* Axis Pixel Length Register */
-#define        HD64461_LNDGR           (CONFIG_HD64461_IOBASE + 0x104c)        /* Diagonal Register */
-#define        HD64461_LNAXR           (CONFIG_HD64461_IOBASE + 0x104e)        /* Axial Register */
-#define        HD64461_LNERTR          (CONFIG_HD64461_IOBASE + 0x1050)        /* Start Error Term Register */
-#define        HD64461_LNMDR           (CONFIG_HD64461_IOBASE + 0x1052)        /* Line Mode Register */
+#define        HD64461_LNSARH          HD64461_IO_OFFSET(0x1046)       /* Line Start Address Register (H) */
+#define        HD64461_LNSARL          HD64461_IO_OFFSET(0x1048)       /* Line Start Address Register (L) */
+#define        HD64461_LNAXLR          HD64461_IO_OFFSET(0x104a)       /* Axis Pixel Length Register */
+#define        HD64461_LNDGR           HD64461_IO_OFFSET(0x104c)       /* Diagonal Register */
+#define        HD64461_LNAXR           HD64461_IO_OFFSET(0x104e)       /* Axial Register */
+#define        HD64461_LNERTR          HD64461_IO_OFFSET(0x1050)       /* Start Error Term Register */
+#define        HD64461_LNMDR           HD64461_IO_OFFSET(0x1052)       /* Line Mode Register */
 
 /* BitBLT Registers */
-#define        HD64461_BBTSSARH        (CONFIG_HD64461_IOBASE + 0x1054)        /* Source Start Address Register (H) */
-#define        HD64461_BBTSSARL        (CONFIG_HD64461_IOBASE + 0x1056)        /* Source Start Address Register (L) */
-#define        HD64461_BBTDSARH        (CONFIG_HD64461_IOBASE + 0x1058)        /* Destination Start Address Register (H) */
-#define        HD64461_BBTDSARL        (CONFIG_HD64461_IOBASE + 0x105a)        /* Destination Start Address Register (L) */
-#define        HD64461_BBTDWR          (CONFIG_HD64461_IOBASE + 0x105c)        /* Destination Block Width Register */
-#define        HD64461_BBTDHR          (CONFIG_HD64461_IOBASE + 0x105e)        /* Destination Block Height Register */
-#define        HD64461_BBTPARH         (CONFIG_HD64461_IOBASE + 0x1060)        /* Pattern Start Address Register (H) */
-#define        HD64461_BBTPARL         (CONFIG_HD64461_IOBASE + 0x1062)        /* Pattern Start Address Register (L) */
-#define        HD64461_BBTMARH         (CONFIG_HD64461_IOBASE + 0x1064)        /* Mask Start Address Register (H) */
-#define        HD64461_BBTMARL         (CONFIG_HD64461_IOBASE + 0x1066)        /* Mask Start Address Register (L) */
-#define        HD64461_BBTROPR         (CONFIG_HD64461_IOBASE + 0x1068)        /* ROP Register */
-#define        HD64461_BBTMDR          (CONFIG_HD64461_IOBASE + 0x106a)        /* BitBLT Mode Register */
+#define        HD64461_BBTSSARH        HD64461_IO_OFFSET(0x1054)       /* Source Start Address Register (H) */
+#define        HD64461_BBTSSARL        HD64461_IO_OFFSET(0x1056)       /* Source Start Address Register (L) */
+#define        HD64461_BBTDSARH        HD64461_IO_OFFSET(0x1058)       /* Destination Start Address Register (H) */
+#define        HD64461_BBTDSARL        HD64461_IO_OFFSET(0x105a)       /* Destination Start Address Register (L) */
+#define        HD64461_BBTDWR          HD64461_IO_OFFSET(0x105c)       /* Destination Block Width Register */
+#define        HD64461_BBTDHR          HD64461_IO_OFFSET(0x105e)       /* Destination Block Height Register */
+#define        HD64461_BBTPARH         HD64461_IO_OFFSET(0x1060)       /* Pattern Start Address Register (H) */
+#define        HD64461_BBTPARL         HD64461_IO_OFFSET(0x1062)       /* Pattern Start Address Register (L) */
+#define        HD64461_BBTMARH         HD64461_IO_OFFSET(0x1064)       /* Mask Start Address Register (H) */
+#define        HD64461_BBTMARL         HD64461_IO_OFFSET(0x1066)       /* Mask Start Address Register (L) */
+#define        HD64461_BBTROPR         HD64461_IO_OFFSET(0x1068)       /* ROP Register */
+#define        HD64461_BBTMDR          HD64461_IO_OFFSET(0x106a)       /* BitBLT Mode Register */
 
 /* PC Card Controller Registers */
 /* Maps to Physical Area 6 */
-#define        HD64461_PCC0ISR         (CONFIG_HD64461_IOBASE + 0x2000)        /* socket 0 interface status */
-#define        HD64461_PCC0GCR         (CONFIG_HD64461_IOBASE + 0x2002)        /* socket 0 general control */
-#define        HD64461_PCC0CSCR        (CONFIG_HD64461_IOBASE + 0x2004)        /* socket 0 card status change */
-#define        HD64461_PCC0CSCIER      (CONFIG_HD64461_IOBASE + 0x2006)        /* socket 0 card status change interrupt enable */
-#define        HD64461_PCC0SCR         (CONFIG_HD64461_IOBASE + 0x2008)        /* socket 0 software control */
+#define        HD64461_PCC0ISR         HD64461_IO_OFFSET(0x2000)       /* socket 0 interface status */
+#define        HD64461_PCC0GCR         HD64461_IO_OFFSET(0x2002)       /* socket 0 general control */
+#define        HD64461_PCC0CSCR        HD64461_IO_OFFSET(0x2004)       /* socket 0 card status change */
+#define        HD64461_PCC0CSCIER      HD64461_IO_OFFSET(0x2006)       /* socket 0 card status change interrupt enable */
+#define        HD64461_PCC0SCR         HD64461_IO_OFFSET(0x2008)       /* socket 0 software control */
 /* Maps to Physical Area 5 */
-#define        HD64461_PCC1ISR         (CONFIG_HD64461_IOBASE + 0x2010)        /* socket 1 interface status */
-#define        HD64461_PCC1GCR         (CONFIG_HD64461_IOBASE + 0x2012)        /* socket 1 general control */
-#define        HD64461_PCC1CSCR        (CONFIG_HD64461_IOBASE + 0x2014)        /* socket 1 card status change */
-#define        HD64461_PCC1CSCIER      (CONFIG_HD64461_IOBASE + 0x2016)        /* socket 1 card status change interrupt enable */
-#define        HD64461_PCC1SCR         (CONFIG_HD64461_IOBASE + 0x2018)        /* socket 1 software control */
+#define        HD64461_PCC1ISR         HD64461_IO_OFFSET(0x2010)       /* socket 1 interface status */
+#define        HD64461_PCC1GCR         HD64461_IO_OFFSET(0x2012)       /* socket 1 general control */
+#define        HD64461_PCC1CSCR        HD64461_IO_OFFSET(0x2014)       /* socket 1 card status change */
+#define        HD64461_PCC1CSCIER      HD64461_IO_OFFSET(0x2016)       /* socket 1 card status change interrupt enable */
+#define        HD64461_PCC1SCR         HD64461_IO_OFFSET(0x2018)       /* socket 1 software control */
 
 /* PCC Interface Status Register */
 #define        HD64461_PCCISR_READY            0x80    /* card ready */
 #define        HD64461_PCCSCR_SWP              0x01    /* write protect */
 
 /* PCC0 Output Pins Control Register */
-#define        HD64461_P0OCR           (CONFIG_HD64461_IOBASE + 0x202a)
+#define        HD64461_P0OCR           HD64461_IO_OFFSET(0x202a)
 
 /* PCC1 Output Pins Control Register */
-#define        HD64461_P1OCR           (CONFIG_HD64461_IOBASE + 0x202c)
+#define        HD64461_P1OCR           HD64461_IO_OFFSET(0x202c)
 
 /* PC Card General Control Register */
-#define        HD64461_PGCR            (CONFIG_HD64461_IOBASE + 0x202e)
+#define        HD64461_PGCR            HD64461_IO_OFFSET(0x202e)
 
 /* Port Control Registers */
-#define        HD64461_GPACR           (CONFIG_HD64461_IOBASE + 0x4000)        /* Port A - Handles IRDA/TIMER */
-#define        HD64461_GPBCR           (CONFIG_HD64461_IOBASE + 0x4002)        /* Port B - Handles UART */
-#define        HD64461_GPCCR           (CONFIG_HD64461_IOBASE + 0x4004)        /* Port C - Handles PCMCIA 1 */
-#define        HD64461_GPDCR           (CONFIG_HD64461_IOBASE + 0x4006)        /* Port D - Handles PCMCIA 1 */
+#define        HD64461_GPACR           HD64461_IO_OFFSET(0x4000)       /* Port A - Handles IRDA/TIMER */
+#define        HD64461_GPBCR           HD64461_IO_OFFSET(0x4002)       /* Port B - Handles UART */
+#define        HD64461_GPCCR           HD64461_IO_OFFSET(0x4004)       /* Port C - Handles PCMCIA 1 */
+#define        HD64461_GPDCR           HD64461_IO_OFFSET(0x4006)       /* Port D - Handles PCMCIA 1 */
 
 /* Port Control Data Registers */
-#define        HD64461_GPADR           (CONFIG_HD64461_IOBASE + 0x4010)        /* A */
-#define        HD64461_GPBDR           (CONFIG_HD64461_IOBASE + 0x4012)        /* B */
-#define        HD64461_GPCDR           (CONFIG_HD64461_IOBASE + 0x4014)        /* C */
-#define        HD64461_GPDDR           (CONFIG_HD64461_IOBASE + 0x4016)        /* D */
+#define        HD64461_GPADR           HD64461_IO_OFFSET(0x4010)       /* A */
+#define        HD64461_GPBDR           HD64461_IO_OFFSET(0x4012)       /* B */
+#define        HD64461_GPCDR           HD64461_IO_OFFSET(0x4014)       /* C */
+#define        HD64461_GPDDR           HD64461_IO_OFFSET(0x4016)       /* D */
 
 /* Interrupt Control Registers */
-#define        HD64461_GPAICR          (CONFIG_HD64461_IOBASE + 0x4020)        /* A */
-#define        HD64461_GPBICR          (CONFIG_HD64461_IOBASE + 0x4022)        /* B */
-#define        HD64461_GPCICR          (CONFIG_HD64461_IOBASE + 0x4024)        /* C */
-#define        HD64461_GPDICR          (CONFIG_HD64461_IOBASE + 0x4026)        /* D */
+#define        HD64461_GPAICR          HD64461_IO_OFFSET(0x4020)       /* A */
+#define        HD64461_GPBICR          HD64461_IO_OFFSET(0x4022)       /* B */
+#define        HD64461_GPCICR          HD64461_IO_OFFSET(0x4024)       /* C */
+#define        HD64461_GPDICR          HD64461_IO_OFFSET(0x4026)       /* D */
 
 /* Interrupt Status Registers */
-#define        HD64461_GPAISR          (CONFIG_HD64461_IOBASE + 0x4040)        /* A */
-#define        HD64461_GPBISR          (CONFIG_HD64461_IOBASE + 0x4042)        /* B */
-#define        HD64461_GPCISR          (CONFIG_HD64461_IOBASE + 0x4044)        /* C */
-#define        HD64461_GPDISR          (CONFIG_HD64461_IOBASE + 0x4046)        /* D */
+#define        HD64461_GPAISR          HD64461_IO_OFFSET(0x4040)       /* A */
+#define        HD64461_GPBISR          HD64461_IO_OFFSET(0x4042)       /* B */
+#define        HD64461_GPCISR          HD64461_IO_OFFSET(0x4044)       /* C */
+#define        HD64461_GPDISR          HD64461_IO_OFFSET(0x4046)       /* D */
 
 /* Interrupt Request Register & Interrupt Mask Register */
-#define        HD64461_NIRR            (CONFIG_HD64461_IOBASE + 0x5000)
-#define        HD64461_NIMR            (CONFIG_HD64461_IOBASE + 0x5002)
+#define        HD64461_NIRR            HD64461_IO_OFFSET(0x5000)
+#define        HD64461_NIMR            HD64461_IO_OFFSET(0x5002)
 
 #define        HD64461_IRQBASE         OFFCHIP_IRQ_BASE
 #define        OFFCHIP_IRQ_BASE        64
index 0454f8d6805917dabb8efb00aa4810fee4520790..25348141674ba0a4f1c806cc1a59715607100820 100644 (file)
@@ -123,10 +123,15 @@ static inline void __raw_reads##bwlq(volatile void __iomem *mem,  \
 
 __BUILD_MEMORY_STRING(b, u8)
 __BUILD_MEMORY_STRING(w, u16)
-__BUILD_MEMORY_STRING(q, u64)
 
+#ifdef CONFIG_SUPERH32
 void __raw_writesl(void __iomem *addr, const void *data, int longlen);
 void __raw_readsl(const void __iomem *addr, void *data, int longlen);
+#else
+__BUILD_MEMORY_STRING(l, u32)
+#endif
+
+__BUILD_MEMORY_STRING(q, u64)
 
 #define writesb                        __raw_writesb
 #define writesw                        __raw_writesw
@@ -224,17 +229,6 @@ void __iomem *__ioremap(unsigned long offset, unsigned long size,
                        unsigned long flags);
 void __iounmap(void __iomem *addr);
 
-/* arch/sh/mm/ioremap_64.c */
-unsigned long onchip_remap(unsigned long addr, unsigned long size,
-                          const char *name);
-extern void onchip_unmap(unsigned long vaddr);
-#else
-#define __ioremap(offset, size, flags) ((void __iomem *)(offset))
-#define __iounmap(addr)                        do { } while (0)
-#define onchip_remap(addr, size, name) (addr)
-#define onchip_unmap(addr)             do { } while (0)
-#endif /* CONFIG_MMU */
-
 static inline void __iomem *
 __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
 {
@@ -268,6 +262,10 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
 
        return __ioremap(offset, size, flags);
 }
+#else
+#define __ioremap_mode(offset, size, flags)    ((void __iomem *)(offset))
+#define __iounmap(addr)                                do { } while (0)
+#endif /* CONFIG_MMU */
 
 #define ioremap(offset, size)                          \
        __ioremap_mode((offset), (size), 0)
index d319baaf4fbdf21a20b65cb659dcfaefd93d5f91..a2b8c99cc06f1a6453bd9162e1e0c34e6a9b0dee 100644 (file)
@@ -8,7 +8,8 @@
  * advised to cap this at the hard limit that they're interested in
  * through the machvec.
  */
-#define NR_IRQS 256
+#define NR_IRQS                        256
+#define NR_IRQS_LEGACY         8       /* Legacy external IRQ0-7 */
 
 /*
  * Convert back and forth between INTEVT and IRQ values.
index 613644a758e8e82b54a975d17376bd63bdd63768..036c3311233cd088d1349c2f9dd1699692153026 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/types.h>
 #include <linux/ptrace.h>
 
-typedef u16 kprobe_opcode_t;
+typedef insn_size_t kprobe_opcode_t;
 #define BREAKPOINT_INSTRUCTION 0xc33a
 
 #define MAX_INSN_SIZE 16
index 64b1c16a0f03559dc53695ccb572c8ca9643de57..84dd37761f563ee56aef820e97d6d1cc844f0936 100644 (file)
@@ -46,6 +46,9 @@ struct sh_machine_vector {
 
        void __iomem *(*mv_ioport_map)(unsigned long port, unsigned int size);
        void (*mv_ioport_unmap)(void __iomem *);
+
+       int (*mv_clk_init)(void);
+       int (*mv_mode_pins)(void);
 };
 
 extern struct sh_machine_vector sh_mv;
index df1d383e18a51e0283b00510f496bec3c7f2aa3b..ae0da6f48b6dc00270d7b3b434c6ba84d85a56a1 100644 (file)
  * external) PCI controllers.
  */
 struct pci_channel {
-       struct pci_ops *pci_ops;
-       struct resource *io_resource;
-       struct resource *mem_resource;
-       int first_devfn;
-       int last_devfn;
-};
+       struct pci_channel      *next;
 
-/*
- * Each board initializes this array and terminates it with a NULL entry.
- */
-extern struct pci_channel board_pci_channels[];
+       struct pci_ops          *pci_ops;
+       struct resource         *io_resource;
+       struct resource         *mem_resource;
 
-#define PCIBIOS_MIN_IO         board_pci_channels->io_resource->start
-#define PCIBIOS_MIN_MEM                board_pci_channels->mem_resource->start
+       unsigned long           io_offset;
+       unsigned long           mem_offset;
 
-/*
- * I/O routine helpers
- */
-#if defined(CONFIG_CPU_SUBTYPE_SH7780) || defined(CONFIG_CPU_SUBTYPE_SH7785)
-#define PCI_IO_AREA            0xFE400000
-#define PCI_IO_SIZE            0x00400000
-#elif defined(CONFIG_CPU_SH5)
-extern unsigned long PCI_IO_AREA;
-#define PCI_IO_SIZE            0x00010000
-#else
-#define PCI_IO_AREA            0xFE240000
-#define PCI_IO_SIZE            0x00040000
-#endif
+       unsigned long           reg_base;
 
-#define PCI_MEM_SIZE           0x01000000
+       unsigned long           io_map_base;
+};
 
-#define SH4_PCIIOBR_MASK       0xFFFC0000
-#define pci_ioaddr(addr)       (PCI_IO_AREA + (addr & ~SH4_PCIIOBR_MASK))
+extern void register_pci_controller(struct pci_channel *hose);
 
-#if defined(CONFIG_PCI)
-#define is_pci_ioaddr(port)            \
-       (((port) >= PCIBIOS_MIN_IO) &&  \
-        ((port) < (PCIBIOS_MIN_IO + PCI_IO_SIZE)))
-#define is_pci_memaddr(port)           \
-       (((port) >= PCIBIOS_MIN_MEM) && \
-        ((port) < (PCIBIOS_MIN_MEM + PCI_MEM_SIZE)))
-#else
-#define is_pci_ioaddr(port)    (0)
-#define is_pci_memaddr(port)   (0)
-#endif
+extern unsigned long PCIBIOS_MIN_IO, PCIBIOS_MIN_MEM;
 
 struct pci_dev;
 
+#define HAVE_PCI_MMAP
+extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+       enum pci_mmap_state mmap_state, int write_combine);
 extern void pcibios_set_master(struct pci_dev *dev);
 
 static inline void pcibios_penalize_isa_irq(int irq, int active)
@@ -114,31 +89,76 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
 #endif
 
 #ifdef CONFIG_PCI
+/*
+ * None of the SH PCI controllers support MWI, it is always treated as a
+ * direct memory write.
+ */
+#define PCI_DISABLE_MWI
+
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
                                        enum pci_dma_burst_strategy *strat,
                                        unsigned long *strategy_parameter)
 {
-       *strat = PCI_DMA_BURST_INFINITY;
-       *strategy_parameter = ~0UL;
+       unsigned long cacheline_size;
+       u8 byte;
+
+       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+
+       if (byte == 0)
+               cacheline_size = L1_CACHE_BYTES;
+       else
+               cacheline_size = byte << 2;
+
+       *strat = PCI_DMA_BURST_MULTIPLE;
+       *strategy_parameter = cacheline_size;
 }
 #endif
 
+#ifdef CONFIG_SUPERH32
+/*
+ * If we're on an SH7751 or SH7780 PCI controller, PCI memory is mapped
+ * at the end of the address space in a special non-translatable area.
+ */
+#define PCI_MEM_FIXED_START    0xfd000000
+#define PCI_MEM_FIXED_END      (PCI_MEM_FIXED_START + 0x01000000)
+
+#define is_pci_memory_fixed_range(s, e)        \
+       ((s) >= PCI_MEM_FIXED_START && (e) < PCI_MEM_FIXED_END)
+#else
+#define is_pci_memory_fixed_range(s, e)        (0)
+#endif
+
 /* Board-specific fixup routines. */
-void pcibios_fixup(void);
-int pcibios_init_platform(void);
 int pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin);
 
-#ifdef CONFIG_PCI_AUTO
-int pciauto_assign_resources(int busno, struct pci_channel *hose);
-#endif
+extern void pcibios_resource_to_bus(struct pci_dev *dev,
+       struct pci_bus_region *region, struct resource *res);
 
-#endif /* __KERNEL__ */
+extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+                                   struct pci_bus_region *region);
 
-/* generic pci stuff */
-#include <asm-generic/pci.h>
+static inline struct resource *
+pcibios_select_root(struct pci_dev *pdev, struct resource *res)
+{
+       struct resource *root = NULL;
+
+       if (res->flags & IORESOURCE_IO)
+               root = &ioport_resource;
+       if (res->flags & IORESOURCE_MEM)
+               root = &iomem_resource;
+
+       return root;
+}
+
+/* Chances are this interrupt is wired PC-style ...  */
+static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
+{
+       return channel ? 15 : 14;
+}
 
 /* generic DMA-mapping stuff */
 #include <asm-generic/pci-dma-compat.h>
 
+#endif /* __KERNEL__ */
 #endif /* __ASM_SH_PCI_H */
 
index b517ae08b9c0f1794a3c72b52aec0cfe181e4294..2a011b18090b64418189db554c564c58bb59e7bf 100644 (file)
@@ -154,6 +154,10 @@ extern void kmap_coherent_init(void);
 #define kmap_coherent_init()   do { } while (0)
 #endif
 
+/* arch/sh/mm/mmap.c */
+#define HAVE_ARCH_UNMAPPED_AREA
+#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
+
 #include <asm-generic/pgtable.h>
 
 #endif /* __ASM_SH_PGTABLE_H */
index 1fd58b421438e87ae141f2b798c39f7bea497294..ff7daaf9a620216ee41ddc0ce1487b1d4af127b3 100644 (file)
@@ -32,7 +32,7 @@ enum cpu_type {
 
        /* SH-4A types */
        CPU_SH7763, CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785, CPU_SH7786,
-       CPU_SH7723, CPU_SHX3,
+       CPU_SH7723, CPU_SH7724, CPU_SHX3,
 
        /* SH4AL-DSP types */
        CPU_SH7343, CPU_SH7722, CPU_SH7366,
@@ -94,6 +94,27 @@ extern struct pt_regs fake_swapper_regs;
 const char *get_cpu_subtype(struct sh_cpuinfo *c);
 extern const struct seq_operations cpuinfo_op;
 
+/* processor boot mode configuration */
+#define MODE_PIN0 (1 << 0)
+#define MODE_PIN1 (1 << 1)
+#define MODE_PIN2 (1 << 2)
+#define MODE_PIN3 (1 << 3)
+#define MODE_PIN4 (1 << 4)
+#define MODE_PIN5 (1 << 5)
+#define MODE_PIN6 (1 << 6)
+#define MODE_PIN7 (1 << 7)
+#define MODE_PIN8 (1 << 8)
+#define MODE_PIN9 (1 << 9)
+#define MODE_PIN10 (1 << 10)
+#define MODE_PIN11 (1 << 11)
+#define MODE_PIN12 (1 << 12)
+#define MODE_PIN13 (1 << 13)
+#define MODE_PIN14 (1 << 14)
+#define MODE_PIN15 (1 << 15)
+
+int generic_mode_pins(void);
+int test_mode_pin(int pin);
+
 #ifdef CONFIG_VSYSCALL
 int vsyscall_init(void);
 #else
index 68e20ff9aa9bbea04e2daf6e9f2d8bd16e615a1b..1dc12cb44a2d7acfa6b918c0f14e5487ed8785ff 100644 (file)
@@ -102,6 +102,11 @@ struct pt_dspregs {
 #define        PTRACE_GETDSPREGS       55      /* DSP registers */
 #define        PTRACE_SETDSPREGS       56
 
+#define PT_TEXT_END_ADDR       240
+#define PT_TEXT_ADDR           244     /* &(struct user)->start_code */
+#define PT_DATA_ADDR           248     /* &(struct user)->start_data */
+#define PT_TEXT_LEN            252
+
 #ifdef __KERNEL__
 #include <asm/addrspace.h>
 
index f7b010d48af7b17d8c6dbf475d105f7839f816a5..52b0c2dba979c8a40c6747bb42e7720ba00d66df 100644 (file)
@@ -6,6 +6,17 @@ extern void (*board_time_init)(void);
 extern void (*rtc_sh_get_time)(struct timespec *);
 extern int (*rtc_sh_set_time)(const time_t);
 
+/* some dummy definitions */
+#define RTC_BATT_BAD 0x100     /* battery bad */
+#define RTC_SQWE 0x08          /* enable square-wave output */
+#define RTC_DM_BINARY 0x04     /* all time/date values are BCD if clear */
+#define RTC_24H 0x02           /* 24 hour mode - else hours bit 7 means pm */
+#define RTC_DST_EN 0x01                /* auto switch DST - works f. USA only */
+
+struct rtc_time;
+unsigned int get_rtc_time(struct rtc_time *);
+int set_rtc_time(struct rtc_time *);
+
 #define RTC_CAP_4_DIGIT_YEAR   (1 << 0)
 
 struct sh_rtc_platform_info {
index 60283565f89b56a83582053a8624cf49fec801b3..a28c9f0053fd4663f52d8c9fc1fb5a78feb31f48 100644 (file)
@@ -26,7 +26,7 @@
 #define __raw_spin_is_locked(x)                ((x)->lock <= 0)
 #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
 #define __raw_spin_unlock_wait(x) \
-       do { cpu_relax(); } while ((x)->lock)
+       do { while (__raw_spin_is_locked(x)) cpu_relax(); } while (0)
 
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
index e69315935107db4f40d7b7b873184e3c67ec9a1e..0e08fe54ad71fcdb30b2a46756736e88bcdd3d34 100644 (file)
@@ -14,15 +14,15 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
 {
        __asm__(
 #ifdef __SH5__
-               "byterev        %0, %0\n\t"
+               "byterev        %1, %0\n\t"
                "shari          %0, 32, %0"
 #else
-               "swap.b         %0, %0\n\t"
+               "swap.b         %1, %0\n\t"
                "swap.w         %0, %0\n\t"
                "swap.b         %0, %0"
 #endif
                : "=r" (x)
-               : "0" (x));
+               : "r" (x));
 
        return x;
 }
@@ -32,13 +32,13 @@ static inline __attribute_const__ __u16 __arch_swab16(__u16 x)
 {
        __asm__(
 #ifdef __SH5__
-               "byterev        %0, %0\n\t"
+               "byterev        %1, %0\n\t"
                "shari          %0, 32, %0"
 #else
-               "swap.b         %0, %0"
+               "swap.b         %1, %0"
 #endif
                : "=r" (x)
-               :  "0" (x));
+               :  "r" (x));
 
        return x;
 }
index 240b31e1142c06f9d254e6c17936d282aef21230..6c68a51f1cc589e7d9773893fa8807aba452645a 100644 (file)
@@ -198,7 +198,7 @@ do {                                                        \
 })
 #endif
 
-int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs,
+int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
                            struct mem_access *ma);
 
 asmlinkage void do_address_error(struct pt_regs *regs,
diff --git a/arch/sh/include/asm/timer.h b/arch/sh/include/asm/timer.h
deleted file mode 100644 (file)
index 4c3b66e..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef __ASM_SH_TIMER_H
-#define __ASM_SH_TIMER_H
-
-#include <linux/sysdev.h>
-#include <linux/clocksource.h>
-#include <cpu/timer.h>
-
-struct sys_timer_ops {
-       int (*init)(void);
-       int (*start)(void);
-       int (*stop)(void);
-#ifndef CONFIG_GENERIC_TIME
-       unsigned long (*get_offset)(void);
-#endif
-};
-
-struct sys_timer {
-       const char              *name;
-
-       struct sys_device       dev;
-       struct sys_timer_ops    *ops;
-};
-
-#define TICK_SIZE (tick_nsec / 1000)
-
-extern struct sys_timer tmu_timer, cmt_timer, mtu2_timer;
-extern struct sys_timer *sys_timer;
-
-#ifndef CONFIG_GENERIC_TIME
-static inline unsigned long get_timer_offset(void)
-{
-       return sys_timer->ops->get_offset();
-}
-#endif
-
-/* arch/sh/kernel/timers/timer.c */
-struct sys_timer *get_sys_timer(void);
-
-/* arch/sh/kernel/time.c */
-void handle_timer_tick(void);
-
-extern struct clocksource clocksource_sh;
-
-#endif /* __ASM_SH_TIMER_H */
index beea4e6f8dfd927c181137016e8b5f1c40e8f59f..b13caca62a768665bd8e0fd9efa29a35615fe123 100644 (file)
@@ -23,9 +23,9 @@ typedef unsigned short umode_t;
 typedef u32 dma_addr_t;
 
 #ifdef CONFIG_SUPERH32
-typedef u16 opcode_t;
+typedef u16 insn_size_t;
 #else
-typedef u32 opcode_t;
+typedef u32 insn_size_t;
 #endif
 
 #endif /* __ASSEMBLY__ */
index a7b9028bbfbb2af8e8da45b3f6b8a927ef1799cb..4ca4b771737135e88ae4b4eac69addfe52d524ca 100644 (file)
 
 #define BRCR_CMFA              (1 << 15)
 #define BRCR_CMFB              (1 << 14)
+
+#if defined CONFIG_CPU_SH2A
+#define BRCR_CMFCA             (1 << 15)
+#define BRCR_CMFCB             (1 << 14)
+#define BRCR_CMFDA             (1 << 13)
+#define BRCR_CMFDB             (1 << 12)
+#define BRCR_PCBB              (1 << 6)        /* 1: after execution */
+#define BRCR_PCBA              (1 << 5)        /* 1: after execution */
+#define BRCR_PCTE              0
+#else
 #define BRCR_PCTE              (1 << 11)
 #define BRCR_PCBA              (1 << 10)       /* 1: after execution */
 #define BRCR_DBEB              (1 << 7)
 #define BRCR_PCBB              (1 << 6)
 #define BRCR_SEQ               (1 << 3)
 #define BRCR_UBDE              (1 << 0)
+#endif
 
 #ifndef __ASSEMBLY__
 /* arch/sh/kernel/cpu/ubc.S */
index d8f89770275bca443434336a71cbd92dfc94757c..9f4dd252c9813e985ebbd5f8cc052256c10b6633 100644 (file)
@@ -3,9 +3,9 @@
 
 /*
  * SH-4A has support for unaligned 32-bit loads, and 32-bit loads only.
- * Support for 16 and 64-bit accesses are done through shifting and
- * masking relative to the endianness. Unaligned stores are not supported
- * by the instruction encoding, so these continue to use the packed
+ * Support for 64-bit accesses are done through shifting and masking
+ * relative to the endianness. Unaligned stores are not supported by the
+ * instruction encoding, so these continue to use the packed
  * struct.
  *
  * The same note as with the movli.l/movco.l pair applies here, as long
@@ -41,9 +41,9 @@ struct __una_u64 { u64 x __attribute__((packed)); };
 static inline u16 __get_unaligned_cpu16(const u8 *p)
 {
 #ifdef __LITTLE_ENDIAN
-       return __get_unaligned_cpu32(p) & 0xffff;
+       return p[0] | p[1] << 8;
 #else
-       return __get_unaligned_cpu32(p) >> 16;
+       return p[0] << 8 | p[1];
 #endif
 }
 
index 2efb819e2db3eeb45ffbb994049560b3be61e552..65197086a1c53ad82b83b6185c1c944fecbb33c9 100644 (file)
 #define __NR_inotify_init1     332
 #define __NR_preadv            333
 #define __NR_pwritev           334
+#define __NR_rt_tgsigqueueinfo 335
 
-#define NR_syscalls 335
+#define NR_syscalls 336
 
 #ifdef __KERNEL__
 
index 6eb9d2934c0f03afaf9da05027a0bce3c9eb2fa3..8014aea88ec3ca405ffae5c094780c10a4869fd3 100644 (file)
 #define __NR_inotify_init1     360
 #define __NR_preadv            361
 #define __NR_pwritev           362
+#define __NR_rt_tgsigqueueinfo 363
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 363
+#define NR_syscalls 364
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 8ce2fc1cf625ad5311854b752a35cc78f8053b28..1192e1c761a7183ceef6d6eaa9ddedb0b8a5ff55 100644 (file)
@@ -1 +1,28 @@
-#include <cpu-sh2/cpu/ubc.h>
+/*
+ * SH-2A UBC definitions
+ *
+ * Copyright (C) 2008 Kieran Bingham
+ *
+ * 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.
+ */
+
+#ifndef __ASM_CPU_SH2A_UBC_H
+#define __ASM_CPU_SH2A_UBC_H
+
+#define UBC_BARA                0xfffc0400
+#define UBC_BAMRA               0xfffc0404
+#define UBC_BBRA                0xfffc04a0     /* 16 bit access */
+#define UBC_BDRA                0xfffc0408
+#define UBC_BDMRA               0xfffc040c
+
+#define UBC_BARB                0xfffc0410
+#define UBC_BAMRB               0xfffc0414
+#define UBC_BBRB                0xfffc04b0     /* 16 bit access */
+#define UBC_BDRB                0xfffc0418
+#define UBC_BDMRB               0xfffc041c
+
+#define UBC_BRCR                0xfffc04c0
+
+#endif /* __ASM_CPU_SH2A_UBC_H */
diff --git a/arch/sh/include/cpu-sh3/cpu/timer.h b/arch/sh/include/cpu-sh3/cpu/timer.h
deleted file mode 100644 (file)
index 793acf1..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * include/asm-sh/cpu-sh3/timer.h
- *
- * Copyright (C) 2004 Lineo Solutions, Inc.
- *
- * 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.
- */
-#ifndef __ASM_CPU_SH3_TIMER_H
-#define __ASM_CPU_SH3_TIMER_H
-
-/*
- * ---------------------------------------------------------------------------
- * TMU Common definitions for SH3 processors
- *     SH7706
- *     SH7709S
- *     SH7727
- *     SH7729R
- *     SH7710
- *     SH7720
- *     SH7710
- * ---------------------------------------------------------------------------
- */
-
-#if  !defined(CONFIG_CPU_SUBTYPE_SH7720) && !defined(CONFIG_CPU_SUBTYPE_SH7721)
-#define TMU_TOCR       0xfffffe90      /* Byte access */
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7710) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721)
-#define TMU_012_TSTR   0xa412fe92      /* Byte access */
-
-#define TMU0_TCOR      0xa412fe94      /* Long access */
-#define TMU0_TCNT      0xa412fe98      /* Long access */
-#define TMU0_TCR       0xa412fe9c      /* Word access */
-
-#define TMU1_TCOR      0xa412fea0      /* Long access */
-#define TMU1_TCNT      0xa412fea4      /* Long access */
-#define TMU1_TCR       0xa412fea8      /* Word access */
-
-#define TMU2_TCOR      0xa412feac      /* Long access */
-#define TMU2_TCNT      0xa412feb0      /* Long access */
-#define TMU2_TCR       0xa412feb4      /* Word access */
-
-#else
-#define TMU_012_TSTR   0xfffffe92      /* Byte access */
-
-#define TMU0_TCOR      0xfffffe94      /* Long access */
-#define TMU0_TCNT      0xfffffe98      /* Long access */
-#define TMU0_TCR       0xfffffe9c      /* Word access */
-
-#define TMU1_TCOR      0xfffffea0      /* Long access */
-#define TMU1_TCNT      0xfffffea4      /* Long access */
-#define TMU1_TCR       0xfffffea8      /* Word access */
-
-#define TMU2_TCOR      0xfffffeac      /* Long access */
-#define TMU2_TCNT      0xfffffeb0      /* Long access */
-#define TMU2_TCR       0xfffffeb4      /* Word access */
-#if !defined(CONFIG_CPU_SUBTYPE_SH7720) && !defined(CONFIG_CPU_SUBTYPE_SH7721)
-#define TMU2_TCPR2     0xfffffeb8      /* Long access */
-#endif
-#endif
-
-#endif /* __ASM_CPU_SH3_TIMER_H */
-
index 1c61ebf5c8e3bfb0a6d025c5d8ca4a338b13027b..7bfb9e8b069c22d789318085e866440502f0c755 100644 (file)
@@ -38,5 +38,7 @@
 #define CACHE_IC_ADDRESS_ARRAY 0xf0000000
 #define CACHE_OC_ADDRESS_ARRAY 0xf4000000
 
+#define RAMCR                  0xFF000074
+
 #endif /* __ASM_CPU_SH4_CACHE_H */
 
index 749d1c43433754beebd7fad01d930dd72266e016..ccf1d999db6daf5f8ac08ba173ec3984b9b38327 100644 (file)
 #elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
       defined(CONFIG_CPU_SUBTYPE_SH7780)
 #define        FRQCR                   0xffc80000
+#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
+#define FRQCRA                 0xa4150000
+#define FRQCRB                 0xa4150004
+#define VCLKCR                 0xa4150048
+
+#define FCLKACR                        0xa4150008
+#define FCLKBCR                        0xa415000c
+#define FRQCR                  FRQCRA
+#define SCLKACR                        FCLKACR
+#define SCLKBCR                        FCLKBCR
+#define FCLKACR                        0xa4150008
+#define FCLKBCR                        0xa415000c
+#define IrDACLKCR              0xa4150018
+
+#define MSTPCR0                        0xa4150030
+#define MSTPCR1                        0xa4150034
+#define MSTPCR2                        0xa4150038
+
 #elif defined(CONFIG_CPU_SUBTYPE_SH7785)
 #define FRQCR0                 0xffc80000
 #define FRQCR1                 0xffc80004
index 4b3096f5307b80a889d1c6f7968f25ef3c826e75..738ea43c5038d72613d940126f2fde0dddbd0aa2 100644 (file)
@@ -1,6 +1,20 @@
 #ifndef __ASM_SH7722_H__
 #define __ASM_SH7722_H__
 
+/* Boot Mode Pins:
+ *
+ * MD0: CPG - Clock Mode 0->3
+ * MD1: CPG - Clock Mode 0->3
+ * MD2: CPG - Reserved (L: Normal operation)
+ * MD3: BSC - Area0 Bus Width (16/32-bit) [CS0BCR.9,10]
+ * MD5: BSC - Endian Mode (L: Big, H: Little) [CMNCR.3]
+ * MD8: Test Mode
+ */
+
+/* Pin Function Controller:
+ * GPIO_FN_xx - GPIO used to select pin function
+ * GPIO_Pxx - GPIO mapped to real I/O pin on CPU
+ */
 enum {
        /* PTA */
        GPIO_PTA7, GPIO_PTA6, GPIO_PTA5, GPIO_PTA4,
index 9d2f6d7aa938d97ea8d789137d1f2e208f7673b6..14c8ca936781c270b6cbcbab7e592430cc57c38e 100644 (file)
@@ -1,6 +1,20 @@
 #ifndef __ASM_SH7723_H__
 #define __ASM_SH7723_H__
 
+/* Boot Mode Pins:
+ *
+ * MD0: CPG - Clock Mode 0->3
+ * MD1: CPG - Clock Mode 0->3
+ * MD2: CPG - Reserved (L: Normal operation)
+ * MD3: BSC - Area0 Bus Width (16/32-bit) [CS0BCR.9,10]
+ * MD5: BSC - Endian Mode (L: Big, H: Little) [CMNCR.3]
+ * MD8: Test Mode
+ */
+
+/* Pin Function Controller:
+ * GPIO_FN_xx - GPIO used to select pin function
+ * GPIO_Pxx - GPIO mapped to real I/O pin on CPU
+ */
 enum {
        /* PTA */
        GPIO_PTA7, GPIO_PTA6, GPIO_PTA5, GPIO_PTA4,
diff --git a/arch/sh/include/cpu-sh4/cpu/sh7724.h b/arch/sh/include/cpu-sh4/cpu/sh7724.h
new file mode 100644 (file)
index 0000000..66fd118
--- /dev/null
@@ -0,0 +1,269 @@
+#ifndef __ASM_SH7724_H__
+#define __ASM_SH7724_H__
+
+/* Boot Mode Pins:
+ *
+ * MD0: CPG - Clock Mode 0->7
+ * MD1: CPG - Clock Mode 0->7
+ * MD2: CPG - Clock Mode 0->7
+ * MD3: BSC - Area0 Bus Width (16/32-bit) [CS0BCR.9,10]
+ * MD5: BSC - Endian Mode (L: Big, H: Little) [CMNCR.3]
+ * MD8: Test Mode
+ */
+
+/* Pin Function Controller:
+ * GPIO_FN_xx - GPIO used to select pin function
+ * GPIO_Pxx - GPIO mapped to real I/O pin on CPU
+ */
+enum {
+       /* PTA */
+       GPIO_PTA7, GPIO_PTA6, GPIO_PTA5, GPIO_PTA4,
+       GPIO_PTA3, GPIO_PTA2, GPIO_PTA1, GPIO_PTA0,
+
+       /* PTB */
+       GPIO_PTB7, GPIO_PTB6, GPIO_PTB5, GPIO_PTB4,
+       GPIO_PTB3, GPIO_PTB2, GPIO_PTB1, GPIO_PTB0,
+
+       /* PTC */
+       GPIO_PTC7, GPIO_PTC6, GPIO_PTC5, GPIO_PTC4,
+       GPIO_PTC3, GPIO_PTC2, GPIO_PTC1, GPIO_PTC0,
+
+       /* PTD */
+       GPIO_PTD7, GPIO_PTD6, GPIO_PTD5, GPIO_PTD4,
+       GPIO_PTD3, GPIO_PTD2, GPIO_PTD1, GPIO_PTD0,
+
+       /* PTE */
+       GPIO_PTE7, GPIO_PTE6, GPIO_PTE5, GPIO_PTE4,
+       GPIO_PTE3, GPIO_PTE2, GPIO_PTE1, GPIO_PTE0,
+
+       /* PTF */
+       GPIO_PTF7, GPIO_PTF6, GPIO_PTF5, GPIO_PTF4,
+       GPIO_PTF3, GPIO_PTF2, GPIO_PTF1, GPIO_PTF0,
+
+       /* PTG */
+                             GPIO_PTG5, GPIO_PTG4,
+       GPIO_PTG3, GPIO_PTG2, GPIO_PTG1, GPIO_PTG0,
+
+       /* PTH */
+       GPIO_PTH7, GPIO_PTH6, GPIO_PTH5, GPIO_PTH4,
+       GPIO_PTH3, GPIO_PTH2, GPIO_PTH1, GPIO_PTH0,
+
+       /* PTJ */
+       GPIO_PTJ7, GPIO_PTJ6, GPIO_PTJ5,
+       GPIO_PTJ3, GPIO_PTJ2, GPIO_PTJ1, GPIO_PTJ0,
+
+       /* PTK */
+       GPIO_PTK7, GPIO_PTK6, GPIO_PTK5, GPIO_PTK4,
+       GPIO_PTK3, GPIO_PTK2, GPIO_PTK1, GPIO_PTK0,
+
+       /* PTL */
+       GPIO_PTL7, GPIO_PTL6, GPIO_PTL5, GPIO_PTL4,
+       GPIO_PTL3, GPIO_PTL2, GPIO_PTL1, GPIO_PTL0,
+
+       /* PTM */
+       GPIO_PTM7, GPIO_PTM6, GPIO_PTM5, GPIO_PTM4,
+       GPIO_PTM3, GPIO_PTM2, GPIO_PTM1, GPIO_PTM0,
+
+       /* PTN */
+       GPIO_PTN7, GPIO_PTN6, GPIO_PTN5, GPIO_PTN4,
+       GPIO_PTN3, GPIO_PTN2, GPIO_PTN1, GPIO_PTN0,
+
+       /* PTQ */
+       GPIO_PTQ7, GPIO_PTQ6, GPIO_PTQ5, GPIO_PTQ4,
+       GPIO_PTQ3, GPIO_PTQ2, GPIO_PTQ1, GPIO_PTQ0,
+
+       /* PTR */
+       GPIO_PTR7, GPIO_PTR6, GPIO_PTR5, GPIO_PTR4,
+       GPIO_PTR3, GPIO_PTR2, GPIO_PTR1, GPIO_PTR0,
+
+       /* PTS */
+                  GPIO_PTS6, GPIO_PTS5, GPIO_PTS4,
+       GPIO_PTS3, GPIO_PTS2, GPIO_PTS1, GPIO_PTS0,
+
+       /* PTT */
+       GPIO_PTT7, GPIO_PTT6, GPIO_PTT5, GPIO_PTT4,
+       GPIO_PTT3, GPIO_PTT2, GPIO_PTT1, GPIO_PTT0,
+
+       /* PTU */
+       GPIO_PTU7, GPIO_PTU6, GPIO_PTU5, GPIO_PTU4,
+       GPIO_PTU3, GPIO_PTU2, GPIO_PTU1, GPIO_PTU0,
+
+       /* PTV */
+       GPIO_PTV7, GPIO_PTV6, GPIO_PTV5, GPIO_PTV4,
+       GPIO_PTV3, GPIO_PTV2, GPIO_PTV1, GPIO_PTV0,
+
+       /* PTW */
+       GPIO_PTW7, GPIO_PTW6, GPIO_PTW5, GPIO_PTW4,
+       GPIO_PTW3, GPIO_PTW2, GPIO_PTW1, GPIO_PTW0,
+
+       /* PTX */
+       GPIO_PTX7, GPIO_PTX6, GPIO_PTX5, GPIO_PTX4,
+       GPIO_PTX3, GPIO_PTX2, GPIO_PTX1, GPIO_PTX0,
+
+       /* PTY */
+       GPIO_PTY7, GPIO_PTY6, GPIO_PTY5, GPIO_PTY4,
+       GPIO_PTY3, GPIO_PTY2, GPIO_PTY1, GPIO_PTY0,
+
+       /* PTZ */
+       GPIO_PTZ7, GPIO_PTZ6, GPIO_PTZ5, GPIO_PTZ4,
+       GPIO_PTZ3, GPIO_PTZ2, GPIO_PTZ1, GPIO_PTZ0,
+
+       /* BSC (PTA/PTB/PTJ/PTQ/PTR/PTT) */
+       GPIO_FN_D31, GPIO_FN_D30, GPIO_FN_D29, GPIO_FN_D28,
+       GPIO_FN_D27, GPIO_FN_D26, GPIO_FN_D25, GPIO_FN_D24,
+       GPIO_FN_D23, GPIO_FN_D22, GPIO_FN_D21, GPIO_FN_D20,
+       GPIO_FN_D19, GPIO_FN_D18, GPIO_FN_D17, GPIO_FN_D16,
+       GPIO_FN_D15, GPIO_FN_D14, GPIO_FN_D13, GPIO_FN_D12,
+       GPIO_FN_D11, GPIO_FN_D10, GPIO_FN_D9,  GPIO_FN_D8,
+       GPIO_FN_D7,  GPIO_FN_D6,  GPIO_FN_D5,  GPIO_FN_D4,
+       GPIO_FN_D3,  GPIO_FN_D2,  GPIO_FN_D1,  GPIO_FN_D0,
+       GPIO_FN_A25, GPIO_FN_A24, GPIO_FN_A23, GPIO_FN_A22,
+       GPIO_FN_CS6B_CE1B,  GPIO_FN_CS6A_CE2B,
+       GPIO_FN_CS5B_CE1A,  GPIO_FN_CS5A_CE2A,
+       GPIO_FN_WE3_ICIOWR, GPIO_FN_WE2_ICIORD,
+       GPIO_FN_IOIS16,     GPIO_FN_WAIT,
+       GPIO_FN_BS,
+
+       /* KEYSC (PTA/PTB)*/
+       GPIO_FN_KEYOUT5_IN5, GPIO_FN_KEYOUT4_IN6, GPIO_FN_KEYIN4,
+       GPIO_FN_KEYIN3,  GPIO_FN_KEYIN2,  GPIO_FN_KEYIN1,  GPIO_FN_KEYIN0,
+       GPIO_FN_KEYOUT3, GPIO_FN_KEYOUT2, GPIO_FN_KEYOUT1, GPIO_FN_KEYOUT0,
+
+       /* ATAPI (PTA/PTB/PTK/PTR/PTS/PTW) */
+       GPIO_FN_IDED15, GPIO_FN_IDED14, GPIO_FN_IDED13, GPIO_FN_IDED12,
+       GPIO_FN_IDED11, GPIO_FN_IDED10, GPIO_FN_IDED9,  GPIO_FN_IDED8,
+       GPIO_FN_IDED7,  GPIO_FN_IDED6,  GPIO_FN_IDED5,  GPIO_FN_IDED4,
+       GPIO_FN_IDED3,  GPIO_FN_IDED2,  GPIO_FN_IDED1,  GPIO_FN_IDED0,
+       GPIO_FN_IDEA2,     GPIO_FN_IDEA1,     GPIO_FN_IDEA0,  GPIO_FN_IDEIOWR,
+       GPIO_FN_IODREQ,    GPIO_FN_IDECS0,    GPIO_FN_IDECS1, GPIO_FN_IDEIORD,
+       GPIO_FN_DIRECTION, GPIO_FN_EXBUF_ENB, GPIO_FN_IDERST, GPIO_FN_IODACK,
+       GPIO_FN_IDEINT,    GPIO_FN_IDEIORDY,
+
+       /* TPU (PTB/PTR/PTS) */
+       GPIO_FN_TPUTO3, GPIO_FN_TPUTO2, GPIO_FN_TPUTO1, GPIO_FN_TPUTO0,
+       GPIO_FN_TPUTI3, GPIO_FN_TPUTI2,
+
+       /* LCDC (PTC/PTD/PTE/PTF/PTM/PTR) */
+       GPIO_FN_LCDD23, GPIO_FN_LCDD22, GPIO_FN_LCDD21, GPIO_FN_LCDD20,
+       GPIO_FN_LCDD19, GPIO_FN_LCDD18, GPIO_FN_LCDD17, GPIO_FN_LCDD16,
+       GPIO_FN_LCDD15, GPIO_FN_LCDD14, GPIO_FN_LCDD13, GPIO_FN_LCDD12,
+       GPIO_FN_LCDD11, GPIO_FN_LCDD10, GPIO_FN_LCDD9,  GPIO_FN_LCDD8,
+       GPIO_FN_LCDD7,  GPIO_FN_LCDD6,  GPIO_FN_LCDD5,  GPIO_FN_LCDD4,
+       GPIO_FN_LCDD3,  GPIO_FN_LCDD2,  GPIO_FN_LCDD1,  GPIO_FN_LCDD0,
+       GPIO_FN_LCDVSYN,  GPIO_FN_LCDDISP,  GPIO_FN_LCDRS,  GPIO_FN_LCDHSYN,
+       GPIO_FN_LCDCS,    GPIO_FN_LCDDON,   GPIO_FN_LCDDCK, GPIO_FN_LCDWR,
+       GPIO_FN_LCDVEPWC, GPIO_FN_LCDVCPWC, GPIO_FN_LCDRD,  GPIO_FN_LCDLCLK,
+
+       /* SCIF0 (PTF/PTM) */
+       GPIO_FN_SCIF0_TXD, GPIO_FN_SCIF0_RXD, GPIO_FN_SCIF0_SCK,
+
+       /* SCIF1 (PTL) */
+       GPIO_FN_SCIF1_SCK, GPIO_FN_SCIF1_RXD, GPIO_FN_SCIF1_TXD,
+
+       /* SCIF2 (PTE/PTF/PTN) with LCDC, VOU */
+       GPIO_FN_SCIF2_L_TXD, GPIO_FN_SCIF2_L_SCK, GPIO_FN_SCIF2_L_RXD,
+       GPIO_FN_SCIF2_V_TXD, GPIO_FN_SCIF2_V_SCK, GPIO_FN_SCIF2_V_RXD,
+
+       /* SCIF3 (PTL/PTN/PTZ) with VOU, IRQ */
+       GPIO_FN_SCIF3_V_SCK, GPIO_FN_SCIF3_V_RXD, GPIO_FN_SCIF3_V_TXD,
+       GPIO_FN_SCIF3_V_CTS, GPIO_FN_SCIF3_V_RTS,
+       GPIO_FN_SCIF3_I_SCK, GPIO_FN_SCIF3_I_RXD, GPIO_FN_SCIF3_I_TXD,
+       GPIO_FN_SCIF3_I_CTS, GPIO_FN_SCIF3_I_RTS,
+
+       /* SCIF4 (PTE) */
+       GPIO_FN_SCIF4_SCK, GPIO_FN_SCIF4_RXD, GPIO_FN_SCIF4_TXD,
+
+       /* SCIF5 (PTS) */
+       GPIO_FN_SCIF5_SCK, GPIO_FN_SCIF5_RXD, GPIO_FN_SCIF5_TXD,
+
+       /* FSI (PTE/PTU/PTV) */
+       GPIO_FN_FSIMCKB,   GPIO_FN_FSIMCKA,    GPIO_FN_FSIOASD,
+       GPIO_FN_FSIIABCK,  GPIO_FN_FSIIALRCK,  GPIO_FN_FSIOABCK,
+       GPIO_FN_FSIOALRCK, GPIO_FN_CLKAUDIOAO, GPIO_FN_FSIIBSD,
+       GPIO_FN_FSIOBSD,   GPIO_FN_FSIIBBCK,   GPIO_FN_FSIIBLRCK,
+       GPIO_FN_FSIOBBCK,  GPIO_FN_FSIOBLRCK,  GPIO_FN_CLKAUDIOBO,
+       GPIO_FN_FSIIASD,
+
+       /* AUD (PTG) */
+       GPIO_FN_AUDCK,   GPIO_FN_AUDSYNC, GPIO_FN_AUDATA3,
+       GPIO_FN_AUDATA2, GPIO_FN_AUDATA1, GPIO_FN_AUDATA0,
+
+       /* VIO (PTS) (common?) */
+       GPIO_FN_VIO_CKO,
+
+       /* VIO0 (PTH/PTK) */
+       GPIO_FN_VIO0_D15, GPIO_FN_VIO0_D14, GPIO_FN_VIO0_D13, GPIO_FN_VIO0_D12,
+       GPIO_FN_VIO0_D11, GPIO_FN_VIO0_D10, GPIO_FN_VIO0_D9,  GPIO_FN_VIO0_D8,
+       GPIO_FN_VIO0_D7,  GPIO_FN_VIO0_D6,  GPIO_FN_VIO0_D5,  GPIO_FN_VIO0_D4,
+       GPIO_FN_VIO0_D3,  GPIO_FN_VIO0_D2,  GPIO_FN_VIO0_D1,  GPIO_FN_VIO0_D0,
+       GPIO_FN_VIO0_VD,  GPIO_FN_VIO0_CLK,
+       GPIO_FN_VIO0_FLD, GPIO_FN_VIO0_HD,
+
+       /* VIO1 (PTK/PTS) */
+       GPIO_FN_VIO1_D7,  GPIO_FN_VIO1_D6, GPIO_FN_VIO1_D5, GPIO_FN_VIO1_D4,
+       GPIO_FN_VIO1_D3,  GPIO_FN_VIO1_D2, GPIO_FN_VIO1_D1, GPIO_FN_VIO1_D0,
+       GPIO_FN_VIO1_FLD, GPIO_FN_VIO1_HD, GPIO_FN_VIO1_VD, GPIO_FN_VIO1_CLK,
+
+       /* Eth  (PTL/PTN/PTX) */
+       GPIO_FN_RMII_RXD0,    GPIO_FN_RMII_RXD1,
+       GPIO_FN_RMII_TXD0,    GPIO_FN_RMII_TXD1,
+       GPIO_FN_RMII_REF_CLK, GPIO_FN_RMII_TX_EN,
+       GPIO_FN_RMII_RX_ER,   GPIO_FN_RMII_CRS_DV,
+       GPIO_FN_LNKSTA,       GPIO_FN_MDIO,
+       GPIO_FN_MDC,
+
+       /* System (PTJ) */
+       GPIO_FN_PDSTATUS, GPIO_FN_STATUS2, GPIO_FN_STATUS0,
+
+       /* VOU (PTL/PTM/PTN*/
+       GPIO_FN_DV_D15,  GPIO_FN_DV_D14, GPIO_FN_DV_D13,   GPIO_FN_DV_D12,
+       GPIO_FN_DV_D11,  GPIO_FN_DV_D10, GPIO_FN_DV_D9,    GPIO_FN_DV_D8,
+       GPIO_FN_DV_D7,   GPIO_FN_DV_D6,  GPIO_FN_DV_D5,    GPIO_FN_DV_D4,
+       GPIO_FN_DV_D3,   GPIO_FN_DV_D2,  GPIO_FN_DV_D1,    GPIO_FN_DV_D0,
+       GPIO_FN_DV_CLKI, GPIO_FN_DV_CLK, GPIO_FN_DV_VSYNC, GPIO_FN_DV_HSYNC,
+
+       /* MSIOF0 (PTL/PTM) */
+       GPIO_FN_MSIOF0_RXD,   GPIO_FN_MSIOF0_TXD,
+       GPIO_FN_MSIOF0_MCK,   GPIO_FN_MSIOF0_TSCK,
+       GPIO_FN_MSIOF0_SS1,   GPIO_FN_MSIOF0_SS2,
+       GPIO_FN_MSIOF0_TSYNC, GPIO_FN_MSIOF0_RSCK,
+       GPIO_FN_MSIOF0_RSYNC,
+
+       /* MSIOF1 (PTV) */
+       GPIO_FN_MSIOF1_RXD,   GPIO_FN_MSIOF1_TXD,
+       GPIO_FN_MSIOF1_MCK,   GPIO_FN_MSIOF1_TSCK,
+       GPIO_FN_MSIOF1_SS1,   GPIO_FN_MSIOF1_SS2,
+       GPIO_FN_MSIOF1_TSYNC, GPIO_FN_MSIOF1_RSCK,
+       GPIO_FN_MSIOF1_RSYNC,
+
+       /* DMAC (PTU/PTX) */
+       GPIO_FN_DMAC_DACK0, GPIO_FN_DMAC_DREQ0,
+       GPIO_FN_DMAC_DACK1, GPIO_FN_DMAC_DREQ1,
+
+       /* SDHI0 (PTY) */
+       GPIO_FN_SDHI0CD, GPIO_FN_SDHI0WP, GPIO_FN_SDHI0CMD, GPIO_FN_SDHI0CLK,
+       GPIO_FN_SDHI0D3, GPIO_FN_SDHI0D2, GPIO_FN_SDHI0D1,  GPIO_FN_SDHI0D0,
+
+       /* SDHI1 (PTW) */
+       GPIO_FN_SDHI1CD, GPIO_FN_SDHI1WP, GPIO_FN_SDHI1CMD, GPIO_FN_SDHI1CLK,
+       GPIO_FN_SDHI1D3, GPIO_FN_SDHI1D2, GPIO_FN_SDHI1D1,  GPIO_FN_SDHI1D0,
+
+       /* MMC (PTW/PTX)*/
+       GPIO_FN_MMC_D7,  GPIO_FN_MMC_D6,  GPIO_FN_MMC_D5, GPIO_FN_MMC_D4,
+       GPIO_FN_MMC_D3,  GPIO_FN_MMC_D2,  GPIO_FN_MMC_D1, GPIO_FN_MMC_D0,
+       GPIO_FN_MMC_CLK, GPIO_FN_MMC_CMD,
+
+       /* IrDA (PTX) */
+       GPIO_FN_IRDA_OUT, GPIO_FN_IRDA_IN,
+
+       /* TSIF (PTX) */
+       GPIO_FN_TSIF_TS0_SDAT, GPIO_FN_TSIF_TS0_SCK,
+       GPIO_FN_TSIF_TS0_SDEN, GPIO_FN_TSIF_TS0_SPSYNC,
+
+       /* IRQ (PTZ) */
+       GPIO_FN_INTC_IRQ7, GPIO_FN_INTC_IRQ6, GPIO_FN_INTC_IRQ5,
+       GPIO_FN_INTC_IRQ4, GPIO_FN_INTC_IRQ3, GPIO_FN_INTC_IRQ2,
+       GPIO_FN_INTC_IRQ1, GPIO_FN_INTC_IRQ0,
+};
+
+#endif /* __ASM_SH7724_H__ */
index e4006afb735ee63820cc160aa78979300390bff4..9dc9d91e0a8e1b9823334cb2af2163653f26e48d 100644 (file)
@@ -1,6 +1,31 @@
 #ifndef __ASM_SH7785_H__
 #define __ASM_SH7785_H__
 
+/* Boot Mode Pins:
+ *
+ * MODE0: CPG - Initial Pck/Bck Frequency [FRQMR1]
+ * MODE1: CPG - Initial Uck/SHck/DDRck Frequency [FRQMR1]
+ * MODE2: CPG - Reserved (L: Normal operation)
+ * MODE3: CPG - Reserved (L: Normal operation)
+ * MODE4: CPG - Initial PLL setting (72x/36x)
+ * MODE5: LBSC - Area0 Memory Type / Bus Width [CS0BCR.8]
+ * MODE6: LBSC - Area0 Memory Type / Bus Width [CS0BCR.9]
+ * MODE7: LBSC - Area0 Memory Type / Bus Width [CS0BCR.3]
+ * MODE8: LBSC - Endian Mode (L: Big, H: Little) [BCR.31]
+ * MODE9: LBSC - Master/Slave Mode (L: Slave) [BCR.30]
+ * MODE10: CPG - Clock Input (L: Ext Clk, H: Crystal)
+ * MODE11: PCI - Pin Mode (LL: PCI host, LH: PCI slave)
+ * MODE12: PCI - Pin Mode (HL: Local bus, HH: DU)
+ * MODE13: Boot Address Mode (L: 29-bit, H: 32-bit)
+ * MODE14: Reserved (H: Normal operation)
+ *
+ * More information in sh7785 manual Rev.1.00, page 1628.
+ */
+
+/* Pin Function Controller:
+ * GPIO_FN_xx - GPIO used to select pin function
+ * GPIO_Pxx - GPIO mapped to real I/O pin on CPU
+ */
 enum {
        /* PA */
        GPIO_PA7, GPIO_PA6, GPIO_PA5, GPIO_PA4,
diff --git a/arch/sh/include/cpu-sh4/cpu/timer.h b/arch/sh/include/cpu-sh4/cpu/timer.h
deleted file mode 100644 (file)
index d1e796b..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * include/asm-sh/cpu-sh4/timer.h
- *
- * Copyright (C) 2004 Lineo Solutions, Inc.
- *
- * 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.
- */
-#ifndef __ASM_CPU_SH4_TIMER_H
-#define __ASM_CPU_SH4_TIMER_H
-
-/*
- * ---------------------------------------------------------------------------
- * TMU Common definitions for SH4 processors
- *     SH7750S/SH7750R
- *     SH7751/SH7751R
- *     SH7760
- *     SH-X3
- * ---------------------------------------------------------------------------
- */
-#ifdef CONFIG_CPU_SUBTYPE_SHX3
-#define TMU_012_BASE   0xffc10000
-#define TMU_345_BASE   0xffc20000
-#else
-#define TMU_012_BASE   0xffd80000
-#define TMU_345_BASE   0xfe100000
-#endif
-
-#define TMU_TOCR       TMU_012_BASE    /* Not supported on all CPUs */
-
-#define TMU_012_TSTR   (TMU_012_BASE + 0x04)
-#define TMU_345_TSTR   (TMU_345_BASE + 0x04)
-
-#define TMU0_TCOR      (TMU_012_BASE + 0x08)
-#define TMU0_TCNT      (TMU_012_BASE + 0x0c)
-#define TMU0_TCR       (TMU_012_BASE + 0x10)
-
-#define TMU1_TCOR       (TMU_012_BASE + 0x14)
-#define TMU1_TCNT       (TMU_012_BASE + 0x18)
-#define TMU1_TCR        (TMU_012_BASE + 0x1c)
-
-#define TMU2_TCOR       (TMU_012_BASE + 0x20)
-#define TMU2_TCNT       (TMU_012_BASE + 0x24)
-#define TMU2_TCR       (TMU_012_BASE + 0x28)
-#define TMU2_TCPR      (TMU_012_BASE + 0x2c)
-
-#define TMU3_TCOR      (TMU_345_BASE + 0x08)
-#define TMU3_TCNT      (TMU_345_BASE + 0x0c)
-#define TMU3_TCR       (TMU_345_BASE + 0x10)
-
-#define TMU4_TCOR      (TMU_345_BASE + 0x14)
-#define TMU4_TCNT      (TMU_345_BASE + 0x18)
-#define TMU4_TCR       (TMU_345_BASE + 0x1c)
-
-#define TMU5_TCOR      (TMU_345_BASE + 0x20)
-#define TMU5_TCNT      (TMU_345_BASE + 0x24)
-#define TMU5_TCR       (TMU_345_BASE + 0x28)
-
-#endif /* __ASM_CPU_SH4_TIMER_H */
index f0f0756e6e8491bab5fbf059dc9535d0bde4d8c4..0ccf257a72d1fa216468a5e871fd48afff35a308 100644 (file)
 #define TOP_PRIORITY   15
 
 extern int intc_evt_to_irq[(0xE20/0x20)+1];
-int intc_irq_describe(char* p, int irq);
 extern int platform_int_priority[NR_INTC_IRQS];
 
 #endif /* __ASM_SH_CPU_SH5_IRQ_H */
index 1ce27d5c749180c5b0534c670ea5bc5f4727ca80..90011d435f304ee57891b2487ecf8ceb4e4065c3 100644 (file)
@@ -9,11 +9,11 @@
  * -----------------------------+---------------+---------------
  * 0x00000000 - 0x03ffffff(CS0)        | NOR Flash     | NOR Flash
  * 0x04000000 - 0x05ffffff(CS1)        | PLD           | PLD
- * 0x06000000 - 0x07ffffff(CS1)        | reserved      | I2C
+ * 0x06000000 - 0x07ffffff(CS1)        | I2C           | I2C
  * 0x08000000 - 0x0bffffff(CS2)        | USB           | DDR SDRAM
  * 0x0c000000 - 0x0fffffff(CS3)        | SD            | DDR SDRAM
  * 0x10000000 - 0x13ffffff(CS4)        | SM107         | SM107
- * 0x14000000 - 0x17ffffff(CS5)        | I2C           | USB
+ * 0x14000000 - 0x17ffffff(CS5)        | reserved      | USB
  * 0x18000000 - 0x1bffffff(CS6)        | reserved      | SD
  * 0x40000000 - 0x5fffffff     | DDR SDRAM     | (cannot use)
  *
@@ -32,6 +32,9 @@
 #define PLD_VERSR              (PLD_BASE_ADDR + 0x0c)
 #define PLD_MMSR               (PLD_BASE_ADDR + 0x0e)
 
+#define PCA9564_ADDR           0x06000000      /* I2C */
+#define PCA9564_SIZE           0x00000100
+
 #define SM107_MEM_ADDR         0x10000000
 #define SM107_MEM_SIZE         0x00e00000
 #define SM107_REG_ADDR         0x13e00000
 #if defined(CONFIG_SH_SH7785LCR_29BIT_PHYSMAPS)
 #define R8A66597_ADDR          0x14000000      /* USB */
 #define CG200_ADDR             0x18000000      /* SD */
-#define PCA9564_ADDR           0x06000000      /* I2C */
 #else
 #define R8A66597_ADDR          0x08000000
 #define CG200_ADDR             0x0c000000
-#define PCA9564_ADDR           0x14000000
 #endif
 
 #define R8A66597_SIZE          0x00000100
 #define CG200_SIZE             0x00010000
-#define PCA9564_SIZE           0x00000100
 
 #endif  /* __ASM_SH_RENESAS_SH7785LCR_H */
 
index 75fc9009e092155384aa670b3f317ee23677ff6a..0314d975e62690f32c9ec50f9f2c7a15ee00849c 100644 (file)
@@ -21,5 +21,7 @@
 
 #define        GAPSPCI_IRQ             HW_EVENT_EXTERNAL
 
+extern struct pci_ops gapspci_pci_ops;
+
 #endif /* __ASM_SH_DREAMCAST_PCI_H */
 
diff --git a/arch/sh/include/mach-se/mach/se7724.h b/arch/sh/include/mach-se/mach/se7724.h
new file mode 100644 (file)
index 0000000..74164b6
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __ASM_SH_SE7724_H
+#define __ASM_SH_SE7724_H
+
+/*
+ * linux/include/asm-sh/se7724.h
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ *
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Hitachi UL SolutionEngine 7724 Support.
+ *
+ * Based on se7722.h
+ * Copyright (C) 2007  Nobuhiro Iwamatsu
+ *
+ * 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.
+ *
+ */
+#include <asm/addrspace.h>
+
+#define PA_LED         (0xba203000)    /* 8bit LED */
+#define IRQ_MODE       (0xba200010)
+#define IRQ0_SR                (0xba200014)
+#define IRQ1_SR                (0xba200018)
+#define IRQ2_SR                (0xba20001c)
+#define IRQ0_MR                (0xba200020)
+#define IRQ1_MR                (0xba200024)
+#define IRQ2_MR                (0xba200028)
+
+/* IRQ */
+#define IRQ0_IRQ        32
+#define IRQ1_IRQ        33
+#define IRQ2_IRQ        34
+
+/* Bits in IRQ012 registers */
+#define SE7724_FPGA_IRQ_BASE   220
+
+/* IRQ0 */
+#define IRQ0_BASE      SE7724_FPGA_IRQ_BASE
+#define IRQ0_KEY       (IRQ0_BASE + 12)
+#define IRQ0_RMII      (IRQ0_BASE + 13)
+#define IRQ0_SMC       (IRQ0_BASE + 14)
+#define IRQ0_MASK      0x7fff
+#define IRQ0_END       IRQ0_SMC
+/* IRQ1 */
+#define IRQ1_BASE      (IRQ0_END + 1)
+#define IRQ1_TS                (IRQ1_BASE + 0)
+#define IRQ1_MASK      0x0001
+#define IRQ1_END       IRQ1_TS
+/* IRQ2 */
+#define IRQ2_BASE      (IRQ1_END + 1)
+#define IRQ2_USB0      (IRQ1_BASE + 0)
+#define IRQ2_USB1      (IRQ1_BASE + 1)
+#define IRQ2_MASK      0x0003
+#define IRQ2_END       IRQ2_USB1
+
+#define SE7724_FPGA_IRQ_NR     (IRQ2_END - IRQ0_BASE)
+
+/* arch/sh/boards/se/7724/irq.c */
+void init_se7724_IRQ(void);
+
+#define __IO_PREFIX            se7724
+#include <asm/io_generic.h>
+
+#endif  /* __ASM_SH_SE7724_H */
index 82a3a150c00da2505add91e5cfb37d43b82bc597..9411e3e31e686d8b45da7b1f5d1a058d3c61c3f2 100644 (file)
@@ -11,10 +11,10 @@ endif
 
 obj-y  := debugtraps.o idle.o io.o io_generic.o irq.o                  \
           machvec.o process_32.o ptrace_32.o setup.o signal_32.o       \
-          sys_sh.o sys_sh32.o syscalls_32.o time_32.o topology.o       \
+          sys_sh.o sys_sh32.o syscalls_32.o time.o topology.o  \
           traps.o traps_32.o
 
-obj-y                          += cpu/ timers/
+obj-y                          += cpu/
 obj-$(CONFIG_VSYSCALL)         += vsyscall/
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o
@@ -32,4 +32,6 @@ obj-$(CONFIG_DYNAMIC_FTRACE)  += ftrace.o
 obj-$(CONFIG_DUMP_CODE)                += disassemble.o
 obj-$(CONFIG_HIBERNATION)      += swsusp.o
 
+obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)    += localtimer.o
+
 EXTRA_CFLAGS += -Werror
index fe425d7f6871be9d43a151723e584b3b438598a4..67b9f6c6326b6bf1cf1cb7d34f024ca1f876958e 100644 (file)
@@ -2,19 +2,18 @@ extra-y       := head_64.o init_task.o vmlinux.lds
 
 obj-y  := debugtraps.o idle.o io.o io_generic.o irq.o machvec.o process_64.o \
           ptrace_64.o setup.o signal_64.o sys_sh.o sys_sh64.o \
-          syscalls_64.o time_64.o topology.o traps.o traps_64.o
+          syscalls_64.o time.o topology.o traps.o traps_64.o
 
-obj-y                          += cpu/ timers/
-obj-$(CONFIG_VSYSCALL)         += vsyscall/
+obj-y                          += cpu/
 obj-$(CONFIG_SMP)              += smp.o
-obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o
 obj-$(CONFIG_SH_CPU_FREQ)      += cpufreq.o
 obj-$(CONFIG_MODULES)          += sh_ksyms_64.o module.o
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
-obj-$(CONFIG_KEXEC)            += machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-$(CONFIG_IO_TRAPPED)       += io_trapped.o
 obj-$(CONFIG_GENERIC_GPIO)     += gpio.o
 
+obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)    += localtimer.o
+
 EXTRA_CFLAGS += -Werror
index 2600641a483f743ab7938f4daf9a42e58111733a..eecad7cbd61e98f70beaa5699c5379f6886624cd 100644 (file)
@@ -17,5 +17,6 @@ obj-$(CONFIG_ARCH_SHMOBILE)   += shmobile/
 
 obj-$(CONFIG_UBC_WAKEUP)       += ubc.o
 obj-$(CONFIG_SH_ADC)           += adc.o
+obj-$(CONFIG_SH_CLK_CPG)       += clock-cpg.o
 
 obj-y  += irq/ init.o clock.o
diff --git a/arch/sh/kernel/cpu/clock-cpg.c b/arch/sh/kernel/cpu/clock-cpg.c
new file mode 100644 (file)
index 0000000..275942e
--- /dev/null
@@ -0,0 +1,256 @@
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/bootmem.h>
+#include <linux/io.h>
+#include <asm/clock.h>
+
+static int sh_clk_mstp32_enable(struct clk *clk)
+{
+       __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << clk->enable_bit),
+                    clk->enable_reg);
+       return 0;
+}
+
+static void sh_clk_mstp32_disable(struct clk *clk)
+{
+       __raw_writel(__raw_readl(clk->enable_reg) | (1 << clk->enable_bit),
+                    clk->enable_reg);
+}
+
+static struct clk_ops sh_clk_mstp32_clk_ops = {
+       .enable         = sh_clk_mstp32_enable,
+       .disable        = sh_clk_mstp32_disable,
+       .recalc         = followparent_recalc,
+};
+
+int __init sh_clk_mstp32_register(struct clk *clks, int nr)
+{
+       struct clk *clkp;
+       int ret = 0;
+       int k;
+
+       for (k = 0; !ret && (k < nr); k++) {
+               clkp = clks + k;
+               clkp->ops = &sh_clk_mstp32_clk_ops;
+               ret |= clk_register(clkp);
+       }
+
+       return ret;
+}
+
+static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
+{
+       return clk_rate_table_round(clk, clk->freq_table, rate);
+}
+
+static int sh_clk_div6_divisors[64] = {
+       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+       33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+       49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
+};
+
+static struct clk_div_mult_table sh_clk_div6_table = {
+       .divisors = sh_clk_div6_divisors,
+       .nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
+};
+
+static unsigned long sh_clk_div6_recalc(struct clk *clk)
+{
+       struct clk_div_mult_table *table = &sh_clk_div6_table;
+       unsigned int idx;
+
+       clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
+                            table, NULL);
+
+       idx = __raw_readl(clk->enable_reg) & 0x003f;
+
+       return clk->freq_table[idx].frequency;
+}
+
+static int sh_clk_div6_set_rate(struct clk *clk,
+                               unsigned long rate, int algo_id)
+{
+       unsigned long value;
+       int idx;
+
+       idx = clk_rate_table_find(clk, clk->freq_table, rate);
+       if (idx < 0)
+               return idx;
+
+       value = __raw_readl(clk->enable_reg);
+       value &= ~0x3f;
+       value |= idx;
+       __raw_writel(value, clk->enable_reg);
+       return 0;
+}
+
+static int sh_clk_div6_enable(struct clk *clk)
+{
+       unsigned long value;
+       int ret;
+
+       ret = sh_clk_div6_set_rate(clk, clk->rate, 0);
+       if (ret == 0) {
+               value = __raw_readl(clk->enable_reg);
+               value &= ~0x100; /* clear stop bit to enable clock */
+               __raw_writel(value, clk->enable_reg);
+       }
+       return ret;
+}
+
+static void sh_clk_div6_disable(struct clk *clk)
+{
+       unsigned long value;
+
+       value = __raw_readl(clk->enable_reg);
+       value |= 0x100; /* stop clock */
+       value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
+       __raw_writel(value, clk->enable_reg);
+}
+
+static struct clk_ops sh_clk_div6_clk_ops = {
+       .recalc         = sh_clk_div6_recalc,
+       .round_rate     = sh_clk_div_round_rate,
+       .set_rate       = sh_clk_div6_set_rate,
+       .enable         = sh_clk_div6_enable,
+       .disable        = sh_clk_div6_disable,
+};
+
+int __init sh_clk_div6_register(struct clk *clks, int nr)
+{
+       struct clk *clkp;
+       void *freq_table;
+       int nr_divs = sh_clk_div6_table.nr_divisors;
+       int freq_table_size = sizeof(struct cpufreq_frequency_table);
+       int ret = 0;
+       int k;
+
+       freq_table_size *= (nr_divs + 1);
+
+       freq_table = alloc_bootmem(freq_table_size * nr);
+       if (!freq_table)
+               return -ENOMEM;
+
+       for (k = 0; !ret && (k < nr); k++) {
+               clkp = clks + k;
+
+               clkp->ops = &sh_clk_div6_clk_ops;
+               clkp->id = -1;
+               clkp->freq_table = freq_table + (k * freq_table_size);
+               clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
+
+               ret = clk_register(clkp);
+       }
+
+       return ret;
+}
+
+static unsigned long sh_clk_div4_recalc(struct clk *clk)
+{
+       struct clk_div_mult_table *table = clk->priv;
+       unsigned int idx;
+
+       clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
+                            table, &clk->arch_flags);
+
+       idx = (__raw_readl(clk->enable_reg) >> clk->enable_bit) & 0x000f;
+
+       return clk->freq_table[idx].frequency;
+}
+
+static struct clk_ops sh_clk_div4_clk_ops = {
+       .recalc         = sh_clk_div4_recalc,
+       .round_rate     = sh_clk_div_round_rate,
+};
+
+int __init sh_clk_div4_register(struct clk *clks, int nr,
+                               struct clk_div_mult_table *table)
+{
+       struct clk *clkp;
+       void *freq_table;
+       int nr_divs = table->nr_divisors;
+       int freq_table_size = sizeof(struct cpufreq_frequency_table);
+       int ret = 0;
+       int k;
+
+       freq_table_size *= (nr_divs + 1);
+
+       freq_table = alloc_bootmem(freq_table_size * nr);
+       if (!freq_table)
+               return -ENOMEM;
+
+       for (k = 0; !ret && (k < nr); k++) {
+               clkp = clks + k;
+
+               clkp->ops = &sh_clk_div4_clk_ops;
+               clkp->id = -1;
+               clkp->priv = table;
+
+               clkp->freq_table = freq_table + (k * freq_table_size);
+               clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
+
+               ret = clk_register(clkp);
+       }
+
+       return ret;
+}
+
+#ifdef CONFIG_SH_CLK_CPG_LEGACY
+static struct clk master_clk = {
+       .name           = "master_clk",
+       .flags          = CLK_ENABLE_ON_INIT,
+       .rate           = CONFIG_SH_PCLK_FREQ,
+};
+
+static struct clk peripheral_clk = {
+       .name           = "peripheral_clk",
+       .parent         = &master_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+static struct clk bus_clk = {
+       .name           = "bus_clk",
+       .parent         = &master_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+static struct clk cpu_clk = {
+       .name           = "cpu_clk",
+       .parent         = &master_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+/*
+ * The ordering of these clocks matters, do not change it.
+ */
+static struct clk *onchip_clocks[] = {
+       &master_clk,
+       &peripheral_clk,
+       &bus_clk,
+       &cpu_clk,
+};
+
+int __init __deprecated cpg_clk_init(void)
+{
+       int i, ret = 0;
+
+       for (i = 0; i < ARRAY_SIZE(onchip_clocks); i++) {
+               struct clk *clk = onchip_clocks[i];
+               arch_init_clk_ops(&clk->ops, i);
+               if (clk->ops)
+                       ret |= clk_register(clk);
+       }
+
+       return ret;
+}
+
+/*
+ * Placeholder for compatability, until the lazy CPUs do this
+ * on their own.
+ */
+int __init __weak arch_clk_init(void)
+{
+       return cpg_clk_init();
+}
+#endif /* CONFIG_SH_CPG_CLK_LEGACY */
index 1dc896483b591169bcf1254b70e4961ed3e88337..f3a46be2ae81c169ffebbd486fec123b643f9118 100644 (file)
@@ -1,15 +1,19 @@
 /*
  * arch/sh/kernel/cpu/clock.c - SuperH clock framework
  *
- *  Copyright (C) 2005, 2006, 2007  Paul Mundt
+ *  Copyright (C) 2005 - 2009  Paul Mundt
  *
  * This clock framework is derived from the OMAP version by:
  *
- *     Copyright (C) 2004 - 2005 Nokia Corporation
+ *     Copyright (C) 2004 - 2008 Nokia Corporation
  *     Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
  *
  *  Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
  *
+ *  With clkdev bits:
+ *
+ *     Copyright (C) 2008 Russell King.
+ *
  * 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.
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/list.h>
-#include <linux/kref.h>
 #include <linux/kobject.h>
 #include <linux/sysdev.h>
 #include <linux/seq_file.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
-#include <linux/proc_fs.h>
+#include <linux/debugfs.h>
+#include <linux/cpufreq.h>
 #include <asm/clock.h>
-#include <asm/timer.h>
+#include <asm/machvec.h>
 
 static LIST_HEAD(clock_list);
 static DEFINE_SPINLOCK(clock_lock);
 static DEFINE_MUTEX(clock_list_sem);
 
-/*
- * Each subtype is expected to define the init routines for these clocks,
- * as each subtype (or processor family) will have these clocks at the
- * very least. These are all provided through the CPG, which even some of
- * the more quirky parts (such as ST40, SH4-202, etc.) still have.
- *
- * The processor-specific code is expected to register any additional
- * clock sources that are of interest.
- */
-static struct clk master_clk = {
-       .name           = "master_clk",
-       .flags          = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
-       .rate           = CONFIG_SH_PCLK_FREQ,
-};
+void clk_rate_table_build(struct clk *clk,
+                         struct cpufreq_frequency_table *freq_table,
+                         int nr_freqs,
+                         struct clk_div_mult_table *src_table,
+                         unsigned long *bitmap)
+{
+       unsigned long mult, div;
+       unsigned long freq;
+       int i;
 
-static struct clk module_clk = {
-       .name           = "module_clk",
-       .parent         = &master_clk,
-       .flags          = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
-};
+       for (i = 0; i < nr_freqs; i++) {
+               div = 1;
+               mult = 1;
 
-static struct clk bus_clk = {
-       .name           = "bus_clk",
-       .parent         = &master_clk,
-       .flags          = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
-};
+               if (src_table->divisors && i < src_table->nr_divisors)
+                       div = src_table->divisors[i];
 
-static struct clk cpu_clk = {
-       .name           = "cpu_clk",
-       .parent         = &master_clk,
-       .flags          = CLK_ALWAYS_ENABLED,
-};
+               if (src_table->multipliers && i < src_table->nr_multipliers)
+                       mult = src_table->multipliers[i];
 
-/*
- * The ordering of these clocks matters, do not change it.
- */
-static struct clk *onchip_clocks[] = {
-       &master_clk,
-       &module_clk,
-       &bus_clk,
-       &cpu_clk,
-};
+               if (!div || !mult || (bitmap && !test_bit(i, bitmap)))
+                       freq = CPUFREQ_ENTRY_INVALID;
+               else
+                       freq = clk->parent->rate * mult / div;
 
-static void propagate_rate(struct clk *clk)
+               freq_table[i].index = i;
+               freq_table[i].frequency = freq;
+       }
+
+       /* Termination entry */
+       freq_table[i].index = i;
+       freq_table[i].frequency = CPUFREQ_TABLE_END;
+}
+
+long clk_rate_table_round(struct clk *clk,
+                         struct cpufreq_frequency_table *freq_table,
+                         unsigned long rate)
 {
-       struct clk *clkp;
+       unsigned long rate_error, rate_error_prev = ~0UL;
+       unsigned long rate_best_fit = rate;
+       unsigned long highest, lowest;
+       int i;
+
+       highest = lowest = 0;
+
+       for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+               unsigned long freq = freq_table[i].frequency;
 
-       list_for_each_entry(clkp, &clock_list, node) {
-               if (likely(clkp->parent != clk))
+               if (freq == CPUFREQ_ENTRY_INVALID)
                        continue;
-               if (likely(clkp->ops && clkp->ops->recalc))
-                       clkp->ops->recalc(clkp);
-               if (unlikely(clkp->flags & CLK_RATE_PROPAGATES))
-                       propagate_rate(clkp);
+
+               if (freq > highest)
+                       highest = freq;
+               if (freq < lowest)
+                       lowest = freq;
+
+               rate_error = abs(freq - rate);
+               if (rate_error < rate_error_prev) {
+                       rate_best_fit = freq;
+                       rate_error_prev = rate_error;
+               }
+
+               if (rate_error == 0)
+                       break;
        }
+
+       if (rate >= highest)
+               rate_best_fit = highest;
+       if (rate <= lowest)
+               rate_best_fit = lowest;
+
+       return rate_best_fit;
 }
 
-static int __clk_enable(struct clk *clk)
+int clk_rate_table_find(struct clk *clk,
+                       struct cpufreq_frequency_table *freq_table,
+                       unsigned long rate)
 {
-       /*
-        * See if this is the first time we're enabling the clock, some
-        * clocks that are always enabled still require "special"
-        * initialization. This is especially true if the clock mode
-        * changes and the clock needs to hunt for the proper set of
-        * divisors to use before it can effectively recalc.
-        */
-       if (unlikely(atomic_read(&clk->kref.refcount) == 1))
-               if (clk->ops && clk->ops->init)
-                       clk->ops->init(clk);
+       int i;
 
-       kref_get(&clk->kref);
+       for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+               unsigned long freq = freq_table[i].frequency;
 
-       if (clk->flags & CLK_ALWAYS_ENABLED)
-               return 0;
+               if (freq == CPUFREQ_ENTRY_INVALID)
+                       continue;
 
-       if (likely(clk->ops && clk->ops->enable))
-               clk->ops->enable(clk);
+               if (freq == rate)
+                       return i;
+       }
 
-       return 0;
+       return -ENOENT;
 }
 
-int clk_enable(struct clk *clk)
+/* Used for clocks that always have same value as the parent clock */
+unsigned long followparent_recalc(struct clk *clk)
 {
-       unsigned long flags;
-       int ret;
-
-       if (!clk)
-               return -EINVAL;
+       return clk->parent ? clk->parent->rate : 0;
+}
 
-       clk_enable(clk->parent);
+int clk_reparent(struct clk *child, struct clk *parent)
+{
+       list_del_init(&child->sibling);
+       if (parent)
+               list_add(&child->sibling, &parent->children);
+       child->parent = parent;
 
-       spin_lock_irqsave(&clock_lock, flags);
-       ret = __clk_enable(clk);
-       spin_unlock_irqrestore(&clock_lock, flags);
+       /* now do the debugfs renaming to reattach the child
+          to the proper parent */
 
-       return ret;
+       return 0;
 }
-EXPORT_SYMBOL_GPL(clk_enable);
 
-static void clk_kref_release(struct kref *kref)
+/* Propagate rate to children */
+void propagate_rate(struct clk *tclk)
 {
-       /* Nothing to do */
+       struct clk *clkp;
+
+       list_for_each_entry(clkp, &tclk->children, sibling) {
+               if (clkp->ops && clkp->ops->recalc)
+                       clkp->rate = clkp->ops->recalc(clkp);
+
+               propagate_rate(clkp);
+       }
 }
 
 static void __clk_disable(struct clk *clk)
 {
-       int count = kref_put(&clk->kref, clk_kref_release);
-
-       if (clk->flags & CLK_ALWAYS_ENABLED)
+       if (clk->usecount == 0) {
+               printk(KERN_ERR "Trying disable clock %s with 0 usecount\n",
+                      clk->name);
+               WARN_ON(1);
                return;
+       }
 
-       if (!count) {   /* count reaches zero, disable the clock */
+       if (!(--clk->usecount)) {
                if (likely(clk->ops && clk->ops->disable))
                        clk->ops->disable(clk);
+               if (likely(clk->parent))
+                       __clk_disable(clk->parent);
        }
 }
 
@@ -160,28 +189,97 @@ void clk_disable(struct clk *clk)
        spin_lock_irqsave(&clock_lock, flags);
        __clk_disable(clk);
        spin_unlock_irqrestore(&clock_lock, flags);
-
-       clk_disable(clk->parent);
 }
 EXPORT_SYMBOL_GPL(clk_disable);
 
+static int __clk_enable(struct clk *clk)
+{
+       int ret = 0;
+
+       if (clk->usecount++ == 0) {
+               if (clk->parent) {
+                       ret = __clk_enable(clk->parent);
+                       if (unlikely(ret))
+                               goto err;
+               }
+
+               if (clk->ops && clk->ops->enable) {
+                       ret = clk->ops->enable(clk);
+                       if (ret) {
+                               if (clk->parent)
+                                       __clk_disable(clk->parent);
+                               goto err;
+                       }
+               }
+       }
+
+       return ret;
+err:
+       clk->usecount--;
+       return ret;
+}
+
+int clk_enable(struct clk *clk)
+{
+       unsigned long flags;
+       int ret;
+
+       if (!clk)
+               return -EINVAL;
+
+       spin_lock_irqsave(&clock_lock, flags);
+       ret = __clk_enable(clk);
+       spin_unlock_irqrestore(&clock_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+static LIST_HEAD(root_clks);
+
+/**
+ * recalculate_root_clocks - recalculate and propagate all root clocks
+ *
+ * Recalculates all root clocks (clocks with no parent), which if the
+ * clock's .recalc is set correctly, should also propagate their rates.
+ * Called at init.
+ */
+void recalculate_root_clocks(void)
+{
+       struct clk *clkp;
+
+       list_for_each_entry(clkp, &root_clks, sibling) {
+               if (clkp->ops && clkp->ops->recalc)
+                       clkp->rate = clkp->ops->recalc(clkp);
+               propagate_rate(clkp);
+       }
+}
+
 int clk_register(struct clk *clk)
 {
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+
+       /*
+        * trap out already registered clocks
+        */
+       if (clk->node.next || clk->node.prev)
+               return 0;
+
        mutex_lock(&clock_list_sem);
 
-       list_add(&clk->node, &clock_list);
-       kref_init(&clk->kref);
+       INIT_LIST_HEAD(&clk->children);
+       clk->usecount = 0;
 
-       mutex_unlock(&clock_list_sem);
+       if (clk->parent)
+               list_add(&clk->sibling, &clk->parent->children);
+       else
+               list_add(&clk->sibling, &root_clks);
 
-       if (clk->flags & CLK_ALWAYS_ENABLED) {
-               pr_debug( "Clock '%s' is ALWAYS_ENABLED\n", clk->name);
-               if (clk->ops && clk->ops->init)
-                       clk->ops->init(clk);
-               if (clk->ops && clk->ops->enable)
-                       clk->ops->enable(clk);
-               pr_debug( "Enabled.");
-       }
+       list_add(&clk->node, &clock_list);
+       if (clk->ops && clk->ops->init)
+               clk->ops->init(clk);
+       mutex_unlock(&clock_list_sem);
 
        return 0;
 }
@@ -190,11 +288,21 @@ EXPORT_SYMBOL_GPL(clk_register);
 void clk_unregister(struct clk *clk)
 {
        mutex_lock(&clock_list_sem);
+       list_del(&clk->sibling);
        list_del(&clk->node);
        mutex_unlock(&clock_list_sem);
 }
 EXPORT_SYMBOL_GPL(clk_unregister);
 
+static void clk_enable_init_clocks(void)
+{
+       struct clk *clkp;
+
+       list_for_each_entry(clkp, &clock_list, node)
+               if (clkp->flags & CLK_ENABLE_ON_INIT)
+                       clk_enable(clkp);
+}
+
 unsigned long clk_get_rate(struct clk *clk)
 {
        return clk->rate;
@@ -210,56 +318,59 @@ EXPORT_SYMBOL_GPL(clk_set_rate);
 int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
 {
        int ret = -EOPNOTSUPP;
+       unsigned long flags;
 
-       if (likely(clk->ops && clk->ops->set_rate)) {
-               unsigned long flags;
+       spin_lock_irqsave(&clock_lock, flags);
 
-               spin_lock_irqsave(&clock_lock, flags);
+       if (likely(clk->ops && clk->ops->set_rate)) {
                ret = clk->ops->set_rate(clk, rate, algo_id);
-               spin_unlock_irqrestore(&clock_lock, flags);
+               if (ret != 0)
+                       goto out_unlock;
+       } else {
+               clk->rate = rate;
+               ret = 0;
        }
 
-       if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
-               propagate_rate(clk);
+       if (clk->ops && clk->ops->recalc)
+               clk->rate = clk->ops->recalc(clk);
 
-       return ret;
-}
-EXPORT_SYMBOL_GPL(clk_set_rate_ex);
+       propagate_rate(clk);
 
-void clk_recalc_rate(struct clk *clk)
-{
-       if (likely(clk->ops && clk->ops->recalc)) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&clock_lock, flags);
-               clk->ops->recalc(clk);
-               spin_unlock_irqrestore(&clock_lock, flags);
-       }
+out_unlock:
+       spin_unlock_irqrestore(&clock_lock, flags);
 
-       if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
-               propagate_rate(clk);
+       return ret;
 }
-EXPORT_SYMBOL_GPL(clk_recalc_rate);
+EXPORT_SYMBOL_GPL(clk_set_rate_ex);
 
 int clk_set_parent(struct clk *clk, struct clk *parent)
 {
+       unsigned long flags;
        int ret = -EINVAL;
-       struct clk *old;
 
        if (!parent || !clk)
                return ret;
+       if (clk->parent == parent)
+               return 0;
 
-       old = clk->parent;
-       if (likely(clk->ops && clk->ops->set_parent)) {
-               unsigned long flags;
-               spin_lock_irqsave(&clock_lock, flags);
-               ret = clk->ops->set_parent(clk, parent);
-               spin_unlock_irqrestore(&clock_lock, flags);
-               clk->parent = (ret ? old : parent);
-       }
+       spin_lock_irqsave(&clock_lock, flags);
+       if (clk->usecount == 0) {
+               if (clk->ops->set_parent)
+                       ret = clk->ops->set_parent(clk, parent);
+               else
+                       ret = clk_reparent(clk, parent);
+
+               if (ret == 0) {
+                       pr_debug("clock: set parent of %s to %s (new rate %ld)\n",
+                                clk->name, clk->parent->name, clk->rate);
+                       if (clk->ops->recalc)
+                               clk->rate = clk->ops->recalc(clk);
+                       propagate_rate(clk);
+               }
+       } else
+               ret = -EBUSY;
+       spin_unlock_irqrestore(&clock_lock, flags);
 
-       if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
-               propagate_rate(clk);
        return ret;
 }
 EXPORT_SYMBOL_GPL(clk_set_parent);
@@ -286,15 +397,70 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
 }
 EXPORT_SYMBOL_GPL(clk_round_rate);
 
+/*
+ * Find the correct struct clk for the device and connection ID.
+ * We do slightly fuzzy matching here:
+ *  An entry with a NULL ID is assumed to be a wildcard.
+ *  If an entry has a device ID, it must match
+ *  If an entry has a connection ID, it must match
+ * Then we take the most specific entry - with the following
+ * order of precidence: dev+con > dev only > con only.
+ */
+static struct clk *clk_find(const char *dev_id, const char *con_id)
+{
+       struct clk_lookup *p;
+       struct clk *clk = NULL;
+       int match, best = 0;
+
+       list_for_each_entry(p, &clock_list, node) {
+               match = 0;
+               if (p->dev_id) {
+                       if (!dev_id || strcmp(p->dev_id, dev_id))
+                               continue;
+                       match += 2;
+               }
+               if (p->con_id) {
+                       if (!con_id || strcmp(p->con_id, con_id))
+                               continue;
+                       match += 1;
+               }
+               if (match == 0)
+                       continue;
+
+               if (match > best) {
+                       clk = p->clk;
+                       best = match;
+               }
+       }
+       return clk;
+}
+
+struct clk *clk_get_sys(const char *dev_id, const char *con_id)
+{
+       struct clk *clk;
+
+       mutex_lock(&clock_list_sem);
+       clk = clk_find(dev_id, con_id);
+       mutex_unlock(&clock_list_sem);
+
+       return clk ? clk : ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL_GPL(clk_get_sys);
+
 /*
  * Returns a clock. Note that we first try to use device id on the bus
  * and clock name. If this fails, we try to use clock name only.
  */
 struct clk *clk_get(struct device *dev, const char *id)
 {
+       const char *dev_id = dev ? dev_name(dev) : NULL;
        struct clk *p, *clk = ERR_PTR(-ENOENT);
        int idno;
 
+       clk = clk_get_sys(dev_id, id);
+       if (clk && !IS_ERR(clk))
+               return clk;
+
        if (dev == NULL || dev->bus != &platform_bus_type)
                idno = -1;
        else
@@ -330,36 +496,6 @@ void clk_put(struct clk *clk)
 }
 EXPORT_SYMBOL_GPL(clk_put);
 
-void __init __attribute__ ((weak))
-arch_init_clk_ops(struct clk_ops **ops, int type)
-{
-}
-
-int __init __attribute__ ((weak))
-arch_clk_init(void)
-{
-       return 0;
-}
-
-static int show_clocks(char *buf, char **start, off_t off,
-                      int len, int *eof, void *data)
-{
-       struct clk *clk;
-       char *p = buf;
-
-       list_for_each_entry_reverse(clk, &clock_list, node) {
-               unsigned long rate = clk_get_rate(clk);
-
-               p += sprintf(p, "%-12s\t: %ld.%02ldMHz\t%s\n", clk->name,
-                            rate / 1000000, (rate % 1000000) / 10000,
-                            ((clk->flags & CLK_ALWAYS_ENABLED) ||
-                             (atomic_read(&clk->kref.refcount) != 1)) ?
-                            "enabled" : "disabled");
-       }
-
-       return p - buf;
-}
-
 #ifdef CONFIG_PM
 static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
 {
@@ -369,20 +505,22 @@ static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
        switch (state.event) {
        case PM_EVENT_ON:
                /* Resumeing from hibernation */
-               if (prev_state.event == PM_EVENT_FREEZE) {
-                       list_for_each_entry(clkp, &clock_list, node)
-                               if (likely(clkp->ops)) {
-                                       unsigned long rate = clkp->rate;
-
-                                       if (likely(clkp->ops->set_parent))
-                                               clkp->ops->set_parent(clkp,
-                                                       clkp->parent);
-                                       if (likely(clkp->ops->set_rate))
-                                               clkp->ops->set_rate(clkp,
-                                                       rate, NO_CHANGE);
-                                       else if (likely(clkp->ops->recalc))
-                                               clkp->ops->recalc(clkp);
-                                       }
+               if (prev_state.event != PM_EVENT_FREEZE)
+                       break;
+
+               list_for_each_entry(clkp, &clock_list, node) {
+                       if (likely(clkp->ops)) {
+                               unsigned long rate = clkp->rate;
+
+                               if (likely(clkp->ops->set_parent))
+                                       clkp->ops->set_parent(clkp,
+                                               clkp->parent);
+                               if (likely(clkp->ops->set_rate))
+                                       clkp->ops->set_rate(clkp,
+                                               rate, NO_CHANGE);
+                               else if (likely(clkp->ops->recalc))
+                                       clkp->rate = clkp->ops->recalc(clkp);
+                       }
                }
                break;
        case PM_EVENT_FREEZE:
@@ -426,34 +564,116 @@ subsys_initcall(clk_sysdev_init);
 
 int __init clk_init(void)
 {
-       int i, ret = 0;
-
-       BUG_ON(!master_clk.rate);
-
-       for (i = 0; i < ARRAY_SIZE(onchip_clocks); i++) {
-               struct clk *clk = onchip_clocks[i];
+       int ret;
 
-               arch_init_clk_ops(&clk->ops, i);
-               ret |= clk_register(clk);
+       ret = arch_clk_init();
+       if (unlikely(ret)) {
+               pr_err("%s: CPU clock registration failed.\n", __func__);
+               return ret;
        }
 
-       ret |= arch_clk_init();
+       if (sh_mv.mv_clk_init) {
+               ret = sh_mv.mv_clk_init();
+               if (unlikely(ret)) {
+                       pr_err("%s: machvec clock initialization failed.\n",
+                              __func__);
+                       return ret;
+               }
+       }
 
        /* Kick the child clocks.. */
-       propagate_rate(&master_clk);
-       propagate_rate(&bus_clk);
+       recalculate_root_clocks();
+
+       /* Enable the necessary init clocks */
+       clk_enable_init_clocks();
 
        return ret;
 }
 
-static int __init clk_proc_init(void)
+/*
+ *     debugfs support to trace clock tree hierarchy and attributes
+ */
+static struct dentry *clk_debugfs_root;
+
+static int clk_debugfs_register_one(struct clk *c)
 {
-       struct proc_dir_entry *p;
-       p = create_proc_read_entry("clocks", S_IRUSR, NULL,
-                                  show_clocks, NULL);
-       if (unlikely(!p))
-               return -EINVAL;
+       int err;
+       struct dentry *d, *child;
+       struct clk *pa = c->parent;
+       char s[255];
+       char *p = s;
+
+       p += sprintf(p, "%s", c->name);
+       if (c->id >= 0)
+               sprintf(p, ":%d", c->id);
+       d = debugfs_create_dir(s, pa ? pa->dentry : clk_debugfs_root);
+       if (!d)
+               return -ENOMEM;
+       c->dentry = d;
+
+       d = debugfs_create_u8("usecount", S_IRUGO, c->dentry, (u8 *)&c->usecount);
+       if (!d) {
+               err = -ENOMEM;
+               goto err_out;
+       }
+       d = debugfs_create_u32("rate", S_IRUGO, c->dentry, (u32 *)&c->rate);
+       if (!d) {
+               err = -ENOMEM;
+               goto err_out;
+       }
+       d = debugfs_create_x32("flags", S_IRUGO, c->dentry, (u32 *)&c->flags);
+       if (!d) {
+               err = -ENOMEM;
+               goto err_out;
+       }
+       return 0;
 
+err_out:
+       d = c->dentry;
+       list_for_each_entry(child, &d->d_subdirs, d_u.d_child)
+               debugfs_remove(child);
+       debugfs_remove(c->dentry);
+       return err;
+}
+
+static int clk_debugfs_register(struct clk *c)
+{
+       int err;
+       struct clk *pa = c->parent;
+
+       if (pa && !pa->dentry) {
+               err = clk_debugfs_register(pa);
+               if (err)
+                       return err;
+       }
+
+       if (!c->dentry) {
+               err = clk_debugfs_register_one(c);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+static int __init clk_debugfs_init(void)
+{
+       struct clk *c;
+       struct dentry *d;
+       int err;
+
+       d = debugfs_create_dir("clock", NULL);
+       if (!d)
+               return -ENOMEM;
+       clk_debugfs_root = d;
+
+       list_for_each_entry(c, &clock_list, node) {
+               err = clk_debugfs_register(c);
+               if (err)
+                       goto err_out;
+       }
        return 0;
+err_out:
+       debugfs_remove(clk_debugfs_root); /* REVISIT: Cleanup correctly */
+       return err;
 }
-subsys_initcall(clk_proc_init);
+late_initcall(clk_debugfs_init);
index d29e69c156f0a75a48cd0322e688c1b5d6f3add8..ad85421099cdd49ba32b48c28065c90004e9a3a5 100644 (file)
@@ -62,6 +62,11 @@ static void __init speculative_execution_init(void)
 #define speculative_execution_init()   do { } while (0)
 #endif
 
+/* 2nd-level cache init */
+void __uses_jump_to_uncached __attribute__ ((weak)) l2_cache_init(void)
+{
+}
+
 /*
  * Generic first-level cache init
  */
@@ -146,6 +151,8 @@ static void __uses_jump_to_uncached cache_init(void)
        flags &= ~CCR_CACHE_ENABLE;
 #endif
 
+       l2_cache_init();
+
        ctrl_outl(flags, CCR);
        back_to_cached();
 }
index 301b505c4278929668bceeee5b2b4b09a4eca06f..6b5d191eec3a98079ce6605a84f71472f89a309e 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/cache.h>
 #include <linux/irq.h>
+#include <linux/bitmap.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 
 /* Bitmap of IRQ masked */
-static unsigned long imask_mask = 0x7fff;
-static int interrupt_priority = 0;
-
-static void enable_imask_irq(unsigned int irq);
-static void disable_imask_irq(unsigned int irq);
-static void shutdown_imask_irq(unsigned int irq);
-static void mask_and_ack_imask(unsigned int);
-static void end_imask_irq(unsigned int irq);
-
 #define IMASK_PRIORITY 15
 
-static unsigned int startup_imask_irq(unsigned int irq)
-{
-       /* Nothing to do */
-       return 0; /* never anything pending */
-}
+static DECLARE_BITMAP(imask_mask, IMASK_PRIORITY);
+static int interrupt_priority;
 
-static struct hw_interrupt_type imask_irq_type = {
-       .typename = "SR.IMASK",
-       .startup = startup_imask_irq,
-       .shutdown = shutdown_imask_irq,
-       .enable = enable_imask_irq,
-       .disable = disable_imask_irq,
-       .ack = mask_and_ack_imask,
-       .end = end_imask_irq
-};
-
-void static inline set_interrupt_registers(int ip)
+static inline void set_interrupt_registers(int ip)
 {
        unsigned long __dummy;
 
@@ -72,42 +51,31 @@ void static inline set_interrupt_registers(int ip)
                     : "t");
 }
 
-static void disable_imask_irq(unsigned int irq)
+static void mask_imask_irq(unsigned int irq)
 {
-       clear_bit(irq, &imask_mask);
+       clear_bit(irq, imask_mask);
        if (interrupt_priority < IMASK_PRIORITY - irq)
                interrupt_priority = IMASK_PRIORITY - irq;
-
        set_interrupt_registers(interrupt_priority);
 }
 
-static void enable_imask_irq(unsigned int irq)
+static void unmask_imask_irq(unsigned int irq)
 {
-       set_bit(irq, &imask_mask);
-       interrupt_priority = IMASK_PRIORITY - ffz(imask_mask);
-
+       set_bit(irq, imask_mask);
+       interrupt_priority = IMASK_PRIORITY -
+               find_first_zero_bit(imask_mask, IMASK_PRIORITY);
        set_interrupt_registers(interrupt_priority);
 }
 
-static void mask_and_ack_imask(unsigned int irq)
-{
-       disable_imask_irq(irq);
-}
-
-static void end_imask_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-               enable_imask_irq(irq);
-}
-
-static void shutdown_imask_irq(unsigned int irq)
-{
-       /* Nothing to do */
-}
+static struct irq_chip imask_irq_chip = {
+       .typename       = "SR.IMASK",
+       .mask           = mask_imask_irq,
+       .unmask         = unmask_imask_irq,
+       .mask_ack       = mask_imask_irq,
+};
 
 void make_imask_irq(unsigned int irq)
 {
-       disable_irq_nosync(irq);
-       irq_desc[irq].chip = &imask_irq_type;
-       enable_irq(irq);
+       set_irq_chip_and_handler_name(irq, &imask_irq_chip,
+                                     handle_level_irq, "level");
 }
index 726f0335da76b059eaa886d76b49f6ed17f7a2b6..6c092f1f55579e7d67641f4504bad9f71f5ee9e2 100644 (file)
@@ -84,7 +84,7 @@ static void disable_intc_irq(unsigned int irq);
 static void mask_and_ack_intc(unsigned int);
 static void end_intc_irq(unsigned int irq);
 
-static struct hw_interrupt_type intc_irq_type = {
+static struct irq_chip intc_irq_type = {
        .typename = "INTC",
        .startup = startup_intc_irq,
        .shutdown = shutdown_intc_irq,
@@ -152,43 +152,13 @@ static void end_intc_irq(unsigned int irq)
        enable_intc_irq(irq);
 }
 
-/* For future use, if we ever support IRLM=0) */
-void make_intc_irq(unsigned int irq)
-{
-       disable_irq_nosync(irq);
-       irq_desc[irq].chip = &intc_irq_type;
-       disable_intc_irq(irq);
-}
-
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
-static int IRQ_to_vectorN[NR_INTC_IRQS] = {
-       0x12, 0x15, 0x18, 0x1B, 0x40, 0x41, 0x42, 0x43, /*  0- 7 */
-         -1,   -1,   -1,   -1, 0x50, 0x51, 0x52, 0x53, /*  8-15 */
-       0x54, 0x55, 0x32, 0x33, 0x34, 0x35, 0x36,   -1, /* 16-23 */
-         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, /* 24-31 */
-       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x38, /* 32-39 */
-        0x39, 0x3A, 0x3B,   -1,   -1,   -1,   -1,   -1, /* 40-47 */
-         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, /* 48-55 */
-         -1,   -1,   -1,   -1,   -1,   -1,   -1, 0x2B, /* 56-63 */
-
-};
-
-int intc_irq_describe(char* p, int irq)
-{
-       if (irq < NR_INTC_IRQS)
-               return sprintf(p, "(0x%3x)", IRQ_to_vectorN[irq]*0x20);
-       else
-               return 0;
-}
-#endif
-
 void __init plat_irq_setup(void)
 {
        unsigned long long __dummy0, __dummy1=~0x00000000100000f0;
        unsigned long reg;
        int i;
 
-       intc_virt = onchip_remap(INTC_BASE, 1024, "INTC");
+       intc_virt = (unsigned long)ioremap_nocache(INTC_BASE, 1024);
        if (!intc_virt) {
                panic("Unable to remap INTC\n");
        }
@@ -196,7 +166,7 @@ void __init plat_irq_setup(void)
 
        /* Set default: per-line enable/disable, priority driven ack/eoi */
        for (i = 0; i < NR_INTC_IRQS; i++)
-               irq_desc[i].chip = &intc_irq_type;
+               set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq);
 
 
        /* Disable all interrupts and set all priorities to 0 to avoid trouble */
index 3eb17ee5540e88d5c7bd99ae133d597af9e049de..808d99a48efb63880be86ec1e7011223d01c9207 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
+#include <linux/topology.h>
 
 static inline struct ipr_desc *get_ipr_desc(unsigned int irq)
 {
@@ -59,10 +60,18 @@ void register_ipr_controller(struct ipr_desc *desc)
 
        for (i = 0; i < desc->nr_irqs; i++) {
                struct ipr_data *p = desc->ipr_data + i;
+               struct irq_desc *irq_desc;
 
                BUG_ON(p->ipr_idx >= desc->nr_offsets);
                BUG_ON(!desc->ipr_offsets[p->ipr_idx]);
 
+               irq_desc = irq_to_desc_alloc_node(p->irq, numa_node_id());
+               if (unlikely(!irq_desc)) {
+                       printk(KERN_INFO "can not get irq_desc for %d\n",
+                              p->irq);
+                       continue;
+               }
+
                disable_irq_nosync(p->irq);
                set_irq_chip_and_handler_name(p->irq, &desc->chip,
                                      handle_level_irq, "level");
index d2c157917999870078cc79c6b2bdaf431cac76d6..4fe863170e315d6ec192b893ab11365951274c14 100644 (file)
@@ -38,32 +38,27 @@ static struct clk_ops sh7619_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FREQCR) & 0x0007);
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
+       return clk->parent->rate / pfc_divisors[idx];
 }
 
 static struct clk_ops sh7619_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
-       clk->rate = clk->parent->rate / pll1rate[(ctrl_inw(FREQCR) >> 8) & 7];
+       return clk->parent->rate / pll1rate[(ctrl_inw(FREQCR) >> 8) & 7];
 }
 
 static struct clk_ops sh7619_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
-{
-       clk->rate = clk->parent->rate;
-}
-
 static struct clk_ops sh7619_cpu_clk_ops = {
-       .recalc         = cpu_clk_recalc,
+       .recalc         = followparent_recalc,
 };
 
 static struct clk_ops *sh7619_clk_ops[] = {
@@ -78,4 +73,3 @@ void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
        if (idx < ARRAY_SIZE(sh7619_clk_ops))
                *ops = sh7619_clk_ops[idx];
 }
-
index 0e32d8e448ca5fa5937011aeb3328d55f2a2b2fa..13798733f2db93f6db46bf40d4347a3162fcde75 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
 
 enum {
        UNUSED = 0,
@@ -109,9 +111,75 @@ static struct platform_device eth_device = {
        .resource = eth_resources,
 };
 
+static struct sh_timer_config cmt0_platform_data = {
+       .name = "CMT0",
+       .channel_offset = 0x02,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 125,
+       .clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt0_resources[] = {
+       [0] = {
+               .name   = "CMT0",
+               .start  = 0xf84a0072,
+               .end    = 0xf84a0077,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 86,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt0_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt0_platform_data,
+       },
+       .resource       = cmt0_resources,
+       .num_resources  = ARRAY_SIZE(cmt0_resources),
+};
+
+static struct sh_timer_config cmt1_platform_data = {
+       .name = "CMT1",
+       .channel_offset = 0x08,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 125,
+       .clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt1_resources[] = {
+       [0] = {
+               .name   = "CMT1",
+               .start  = 0xf84a0078,
+               .end    = 0xf84a007d,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 87,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt1_device = {
+       .name           = "sh_cmt",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &cmt1_platform_data,
+       },
+       .resource       = cmt1_resources,
+       .num_resources  = ARRAY_SIZE(cmt1_resources),
+};
+
 static struct platform_device *sh7619_devices[] __initdata = {
        &sci_device,
        &eth_device,
+       &cmt0_device,
+       &cmt1_device,
 };
 
 static int __init sh7619_devices_setup(void)
@@ -125,3 +193,19 @@ void __init plat_irq_setup(void)
 {
        register_intc_controller(&intc_desc);
 }
+
+static struct platform_device *sh7619_early_devices[] __initdata = {
+       &cmt0_device,
+       &cmt1_device,
+};
+
+#define STBCR3 0xf80a0000
+
+void __init plat_early_device_setup(void)
+{
+       /* enable CMT clock */
+       __raw_writeb(__raw_readb(STBCR3) & ~0x10, STBCR3);
+
+       early_platform_add_devices(sh7619_early_devices,
+                                  ARRAY_SIZE(sh7619_early_devices));
+}
index 4a5e59732334ca70782a167c5eccaf4e133b9ffd..7814c76159a7299fdcd512bf7d62b1cf8ce782a7 100644 (file)
@@ -34,37 +34,37 @@ static const int pfc_divisors[]={1,2,3,4,6,8,12};
 
 static void master_clk_init(struct clk *clk)
 {
-       clk->rate = 10000000 * PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007];
+       return 10000000 * PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007];
 }
 
 static struct clk_ops sh7201_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FREQCR) & 0x0007);
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
+       return clk->parent->rate / pfc_divisors[idx];
 }
 
 static struct clk_ops sh7201_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FREQCR) & 0x0007);
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
+       return clk->parent->rate / pfc_divisors[idx];
 }
 
 static struct clk_ops sh7201_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
+static unsigned long cpu_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inw(FREQCR) >> 4) & 0x0007);
-       clk->rate = clk->parent->rate / ifc_divisors[idx];
+       return clk->parent->rate / ifc_divisors[idx];
 }
 
 static struct clk_ops sh7201_cpu_clk_ops = {
index fb781329848af930b22290d452fe99a8fdc7a169..940986965102468535ce920668d83e2f3d3827ba 100644 (file)
@@ -46,33 +46,28 @@ static struct clk_ops sh7203_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FREQCR) & 0x0007);
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
+       return clk->parent->rate / pfc_divisors[idx];
 }
 
 static struct clk_ops sh7203_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FREQCR) & 0x0007);
-       clk->rate = clk->parent->rate / pfc_divisors[idx-2];
+       return clk->parent->rate / pfc_divisors[idx-2];
 }
 
 static struct clk_ops sh7203_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
-{
-       clk->rate = clk->parent->rate;
-}
-
 static struct clk_ops sh7203_cpu_clk_ops = {
-       .recalc         = cpu_clk_recalc,
+       .recalc         = followparent_recalc,
 };
 
 static struct clk_ops *sh7203_clk_ops[] = {
index 82d7f991ef6bd8acb3da60c2238b18c69ebc616a..c2268bdeceeb80a30d6522041e40433b5f2518bb 100644 (file)
@@ -41,29 +41,29 @@ static struct clk_ops sh7206_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FREQCR) & 0x0007);
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
+       return clk->parent->rate / pfc_divisors[idx];
 }
 
 static struct clk_ops sh7206_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
-       clk->rate = clk->parent->rate / pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007];
+       return clk->parent->rate / pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007];
 }
 
 static struct clk_ops sh7206_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
+static unsigned long cpu_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FREQCR) & 0x0007);
-       clk->rate = clk->parent->rate / ifc_divisors[idx];
+       return clk->parent->rate / ifc_divisors[idx];
 }
 
 static struct clk_ops sh7206_cpu_clk_ops = {
index 844293723cfc8239ef7453c09bdb119e71b569f0..869c2da4820b3b763142146ab1b16deb288dcc06 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
 
 enum {
        UNUSED = 0,
@@ -24,7 +25,7 @@ enum {
 
        SCIF0, SCIF1,
 
-       MTU2_GROUP1, MTU2_GROUP2, MTU2_GROUP3, MTU2_GROUP4, MTU2_GROUP5
+       MTU2_GROUP1, MTU2_GROUP2, MTU2_GROUP3, MTU2_GROUP4, MTU2_GROUP5,
        MTU2_TGI3B, MTU2_TGI3C,
 
        /* interrupt groups */
@@ -113,6 +114,99 @@ static struct intc_mask_reg mask_registers[] __initdata = {
 static DECLARE_INTC_DESC(intc_desc, "mxg", vectors, groups,
                         mask_registers, prio_registers, NULL);
 
+static struct sh_timer_config mtu2_0_platform_data = {
+       .name = "MTU2_0",
+       .channel_offset = -0x80,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_0_resources[] = {
+       [0] = {
+               .name   = "MTU2_0",
+               .start  = 0xff801300,
+               .end    = 0xff801326,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 228,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_0_device = {
+       .name           = "sh_mtu2",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &mtu2_0_platform_data,
+       },
+       .resource       = mtu2_0_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_0_resources),
+};
+
+static struct sh_timer_config mtu2_1_platform_data = {
+       .name = "MTU2_1",
+       .channel_offset = -0x100,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_1_resources[] = {
+       [0] = {
+               .name   = "MTU2_1",
+               .start  = 0xff801380,
+               .end    = 0xff801390,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 234,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_1_device = {
+       .name           = "sh_mtu2",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &mtu2_1_platform_data,
+       },
+       .resource       = mtu2_1_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_1_resources),
+};
+
+static struct sh_timer_config mtu2_2_platform_data = {
+       .name = "MTU2_2",
+       .channel_offset = 0x80,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_2_resources[] = {
+       [0] = {
+               .name   = "MTU2_2",
+               .start  = 0xff801000,
+               .end    = 0xff80100a,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 240,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_2_device = {
+       .name           = "sh_mtu2",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &mtu2_2_platform_data,
+       },
+       .resource       = mtu2_2_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_2_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xff804000,
@@ -134,6 +228,9 @@ static struct platform_device sci_device = {
 
 static struct platform_device *mxg_devices[] __initdata = {
        &sci_device,
+       &mtu2_0_device,
+       &mtu2_1_device,
+       &mtu2_2_device,
 };
 
 static int __init mxg_devices_setup(void)
@@ -147,3 +244,15 @@ void __init plat_irq_setup(void)
 {
        register_intc_controller(&intc_desc);
 }
+
+static struct platform_device *mxg_early_devices[] __initdata = {
+       &mtu2_0_device,
+       &mtu2_1_device,
+       &mtu2_2_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(mxg_early_devices,
+                                  ARRAY_SIZE(mxg_early_devices));
+}
index 00f42f9e3f5c6bfec5c23897b1019fdeb9aefdd6..d8febe12806620cee8058b874a454039bc029f89 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
 
 enum {
        UNUSED = 0,
@@ -249,9 +251,105 @@ static struct platform_device rtc_device = {
        .resource       = rtc_resources,
 };
 
+static struct sh_timer_config mtu2_0_platform_data = {
+       .name = "MTU2_0",
+       .channel_offset = -0x80,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_0_resources[] = {
+       [0] = {
+               .name   = "MTU2_0",
+               .start  = 0xfffe4300,
+               .end    = 0xfffe4326,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 108,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_0_device = {
+       .name           = "sh_mtu2",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &mtu2_0_platform_data,
+       },
+       .resource       = mtu2_0_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_0_resources),
+};
+
+static struct sh_timer_config mtu2_1_platform_data = {
+       .name = "MTU2_1",
+       .channel_offset = -0x100,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_1_resources[] = {
+       [0] = {
+               .name   = "MTU2_1",
+               .start  = 0xfffe4380,
+               .end    = 0xfffe4390,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 116,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_1_device = {
+       .name           = "sh_mtu2",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &mtu2_1_platform_data,
+       },
+       .resource       = mtu2_1_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_1_resources),
+};
+
+static struct sh_timer_config mtu2_2_platform_data = {
+       .name = "MTU2_2",
+       .channel_offset = 0x80,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_2_resources[] = {
+       [0] = {
+               .name   = "MTU2_2",
+               .start  = 0xfffe4000,
+               .end    = 0xfffe400a,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 124,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_2_device = {
+       .name           = "sh_mtu2",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &mtu2_2_platform_data,
+       },
+       .resource       = mtu2_2_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_2_resources),
+};
+
 static struct platform_device *sh7201_devices[] __initdata = {
        &sci_device,
        &rtc_device,
+       &mtu2_0_device,
+       &mtu2_1_device,
+       &mtu2_2_device,
 };
 
 static int __init sh7201_devices_setup(void)
@@ -265,3 +363,20 @@ void __init plat_irq_setup(void)
 {
        register_intc_controller(&intc_desc);
 }
+
+static struct platform_device *sh7201_early_devices[] __initdata = {
+       &mtu2_0_device,
+       &mtu2_1_device,
+       &mtu2_2_device,
+};
+
+#define STBCR3 0xfffe0408
+
+void __init plat_early_device_setup(void)
+{
+       /* enable MTU2 clock */
+       __raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
+
+       early_platform_add_devices(sh7201_early_devices,
+                                  ARRAY_SIZE(sh7201_early_devices));
+}
index 820dfb2e8656354e7972ccfc55371695c53e72f4..62e3039d2398ad0071044b0d1f4a7423d08e9d4d 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
 
 enum {
        UNUSED = 0,
@@ -205,6 +207,132 @@ static struct platform_device sci_device = {
        },
 };
 
+static struct sh_timer_config cmt0_platform_data = {
+       .name = "CMT0",
+       .channel_offset = 0x02,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 125,
+       .clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt0_resources[] = {
+       [0] = {
+               .name   = "CMT0",
+               .start  = 0xfffec002,
+               .end    = 0xfffec007,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 142,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt0_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt0_platform_data,
+       },
+       .resource       = cmt0_resources,
+       .num_resources  = ARRAY_SIZE(cmt0_resources),
+};
+
+static struct sh_timer_config cmt1_platform_data = {
+       .name = "CMT1",
+       .channel_offset = 0x08,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 125,
+       .clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt1_resources[] = {
+       [0] = {
+               .name   = "CMT1",
+               .start  = 0xfffec008,
+               .end    = 0xfffec00d,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 143,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt1_device = {
+       .name           = "sh_cmt",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &cmt1_platform_data,
+       },
+       .resource       = cmt1_resources,
+       .num_resources  = ARRAY_SIZE(cmt1_resources),
+};
+
+static struct sh_timer_config mtu2_0_platform_data = {
+       .name = "MTU2_0",
+       .channel_offset = -0x80,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_0_resources[] = {
+       [0] = {
+               .name   = "MTU2_0",
+               .start  = 0xfffe4300,
+               .end    = 0xfffe4326,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 146,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_0_device = {
+       .name           = "sh_mtu2",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &mtu2_0_platform_data,
+       },
+       .resource       = mtu2_0_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_0_resources),
+};
+
+static struct sh_timer_config mtu2_1_platform_data = {
+       .name = "MTU2_1",
+       .channel_offset = -0x100,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_1_resources[] = {
+       [0] = {
+               .name   = "MTU2_1",
+               .start  = 0xfffe4380,
+               .end    = 0xfffe4390,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 153,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_1_device = {
+       .name           = "sh_mtu2",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &mtu2_1_platform_data,
+       },
+       .resource       = mtu2_1_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_1_resources),
+};
+
 static struct resource rtc_resources[] = {
        [0] = {
                .start  = 0xffff2000,
@@ -227,6 +355,10 @@ static struct platform_device rtc_device = {
 
 static struct platform_device *sh7203_devices[] __initdata = {
        &sci_device,
+       &cmt0_device,
+       &cmt1_device,
+       &mtu2_0_device,
+       &mtu2_1_device,
        &rtc_device,
 };
 
@@ -241,3 +373,25 @@ void __init plat_irq_setup(void)
 {
        register_intc_controller(&intc_desc);
 }
+
+static struct platform_device *sh7203_early_devices[] __initdata = {
+       &cmt0_device,
+       &cmt1_device,
+       &mtu2_0_device,
+       &mtu2_1_device,
+};
+
+#define STBCR3 0xfffe0408
+#define STBCR4 0xfffe040c
+
+void __init plat_early_device_setup(void)
+{
+       /* enable CMT clock */
+       __raw_writeb(__raw_readb(STBCR4) & ~0x04, STBCR4);
+
+       /* enable MTU2 clock */
+       __raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
+
+       early_platform_add_devices(sh7203_early_devices,
+                                  ARRAY_SIZE(sh7203_early_devices));
+}
index c46a8355726d18f766dd8d5b92443ade34cdc059..3e6f3d7a58be990cbaa06b5022ab1624be92b8fb 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
 
 enum {
        UNUSED = 0,
@@ -165,8 +167,170 @@ static struct platform_device sci_device = {
        },
 };
 
+static struct sh_timer_config cmt0_platform_data = {
+       .name = "CMT0",
+       .channel_offset = 0x02,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 125,
+       .clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt0_resources[] = {
+       [0] = {
+               .name   = "CMT0",
+               .start  = 0xfffec002,
+               .end    = 0xfffec007,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 140,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt0_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt0_platform_data,
+       },
+       .resource       = cmt0_resources,
+       .num_resources  = ARRAY_SIZE(cmt0_resources),
+};
+
+static struct sh_timer_config cmt1_platform_data = {
+       .name = "CMT1",
+       .channel_offset = 0x08,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 125,
+       .clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt1_resources[] = {
+       [0] = {
+               .name   = "CMT1",
+               .start  = 0xfffec008,
+               .end    = 0xfffec00d,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 144,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt1_device = {
+       .name           = "sh_cmt",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &cmt1_platform_data,
+       },
+       .resource       = cmt1_resources,
+       .num_resources  = ARRAY_SIZE(cmt1_resources),
+};
+
+static struct sh_timer_config mtu2_0_platform_data = {
+       .name = "MTU2_0",
+       .channel_offset = -0x80,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_0_resources[] = {
+       [0] = {
+               .name   = "MTU2_0",
+               .start  = 0xfffe4300,
+               .end    = 0xfffe4326,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 156,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_0_device = {
+       .name           = "sh_mtu2",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &mtu2_0_platform_data,
+       },
+       .resource       = mtu2_0_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_0_resources),
+};
+
+static struct sh_timer_config mtu2_1_platform_data = {
+       .name = "MTU2_1",
+       .channel_offset = -0x100,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_1_resources[] = {
+       [0] = {
+               .name   = "MTU2_1",
+               .start  = 0xfffe4380,
+               .end    = 0xfffe4390,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 164,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_1_device = {
+       .name           = "sh_mtu2",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &mtu2_1_platform_data,
+       },
+       .resource       = mtu2_1_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_1_resources),
+};
+
+static struct sh_timer_config mtu2_2_platform_data = {
+       .name = "MTU2_2",
+       .channel_offset = 0x80,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_2_resources[] = {
+       [0] = {
+               .name   = "MTU2_2",
+               .start  = 0xfffe4000,
+               .end    = 0xfffe400a,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 180,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_2_device = {
+       .name           = "sh_mtu2",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &mtu2_2_platform_data,
+       },
+       .resource       = mtu2_2_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_2_resources),
+};
+
 static struct platform_device *sh7206_devices[] __initdata = {
        &sci_device,
+       &cmt0_device,
+       &cmt1_device,
+       &mtu2_0_device,
+       &mtu2_1_device,
+       &mtu2_2_device,
 };
 
 static int __init sh7206_devices_setup(void)
@@ -180,3 +344,26 @@ void __init plat_irq_setup(void)
 {
        register_intc_controller(&intc_desc);
 }
+
+static struct platform_device *sh7206_early_devices[] __initdata = {
+       &cmt0_device,
+       &cmt1_device,
+       &mtu2_0_device,
+       &mtu2_1_device,
+       &mtu2_2_device,
+};
+
+#define STBCR3 0xfffe0408
+#define STBCR4 0xfffe040c
+
+void __init plat_early_device_setup(void)
+{
+       /* enable CMT clock */
+       __raw_writeb(__raw_readb(STBCR4) & ~0x04, STBCR4);
+
+       /* enable MTU2 clock */
+       __raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
+
+       early_platform_add_devices(sh7206_early_devices,
+                                  ARRAY_SIZE(sh7206_early_devices));
+}
index c3c945958baf6f74472a28a8d49750cbc2632133..27b8738f0b0986d5b255e5cfe2b63dc4b33d13c1 100644 (file)
@@ -38,36 +38,36 @@ static struct clk_ops sh3_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int frqcr = ctrl_inw(FRQCR);
        int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
 
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
+       return clk->parent->rate / pfc_divisors[idx];
 }
 
 static struct clk_ops sh3_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
        int frqcr = ctrl_inw(FRQCR);
        int idx = ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4);
 
-       clk->rate = clk->parent->rate / stc_multipliers[idx];
+       return clk->parent->rate / stc_multipliers[idx];
 }
 
 static struct clk_ops sh3_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
+static unsigned long cpu_clk_recalc(struct clk *clk)
 {
        int frqcr = ctrl_inw(FRQCR);
        int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2);
 
-       clk->rate = clk->parent->rate / ifc_divisors[idx];
+       return clk->parent->rate / ifc_divisors[idx];
 }
 
 static struct clk_ops sh3_cpu_clk_ops = {
index dfdbf3277fd7dda3b73b4244fc55a73c3078a70a..0ca8f2c3646c558be6bbf8c9da0ed64cc25e2b54 100644 (file)
@@ -39,30 +39,30 @@ static struct clk_ops sh7705_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int idx = ctrl_inw(FRQCR) & 0x0003;
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
+       return clk->parent->rate / pfc_divisors[idx];
 }
 
 static struct clk_ops sh7705_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FRQCR) & 0x0300) >> 8;
-       clk->rate = clk->parent->rate / stc_multipliers[idx];
+       return clk->parent->rate / stc_multipliers[idx];
 }
 
 static struct clk_ops sh7705_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
+static unsigned long cpu_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FRQCR) & 0x0030) >> 4;
-       clk->rate = clk->parent->rate / ifc_divisors[idx];
+       return clk->parent->rate / ifc_divisors[idx];
 }
 
 static struct clk_ops sh7705_cpu_clk_ops = {
index 0cf96f9833bcbceaa1e09c25e84ac02061114a97..4bf7887d310af2cf1b59bc1088ab52835279bf37 100644 (file)
@@ -34,36 +34,36 @@ static struct clk_ops sh7706_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int frqcr = ctrl_inw(FRQCR);
        int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
 
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
+       return clk->parent->rate / pfc_divisors[idx];
 }
 
 static struct clk_ops sh7706_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
        int frqcr = ctrl_inw(FRQCR);
        int idx = ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4);
 
-       clk->rate = clk->parent->rate / stc_multipliers[idx];
+       return clk->parent->rate / stc_multipliers[idx];
 }
 
 static struct clk_ops sh7706_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
+static unsigned long cpu_clk_recalc(struct clk *clk)
 {
        int frqcr = ctrl_inw(FRQCR);
        int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2);
 
-       clk->rate = clk->parent->rate / ifc_divisors[idx];
+       return clk->parent->rate / ifc_divisors[idx];
 }
 
 static struct clk_ops sh7706_cpu_clk_ops = {
index b791a29fdb6245773c045eb55ab5e39e2e830e79..fa30b601773040d6246071e3dce54fdc1abaad61 100644 (file)
@@ -41,12 +41,12 @@ static struct clk_ops sh7709_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int frqcr = ctrl_inw(FRQCR);
        int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
 
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
+       return clk->parent->rate / pfc_divisors[idx];
 }
 
 static struct clk_ops sh7709_module_clk_ops = {
@@ -56,25 +56,25 @@ static struct clk_ops sh7709_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
        int frqcr = ctrl_inw(FRQCR);
        int idx = (frqcr & 0x0080) ?
                ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4) : 1;
 
-       clk->rate = clk->parent->rate * stc_multipliers[idx];
+       return clk->parent->rate * stc_multipliers[idx];
 }
 
 static struct clk_ops sh7709_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
+static unsigned long cpu_clk_recalc(struct clk *clk)
 {
        int frqcr = ctrl_inw(FRQCR);
        int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2);
 
-       clk->rate = clk->parent->rate / ifc_divisors[idx];
+       return clk->parent->rate / ifc_divisors[idx];
 }
 
 static struct clk_ops sh7709_cpu_clk_ops = {
index 4744c50ec449cd61a97d04e725bfe5662b7209b2..030a58ba18a5070c6c36ce50c01d4e18a2fcca49 100644 (file)
@@ -33,30 +33,30 @@ static struct clk_ops sh7710_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FRQCR) & 0x0007);
-       clk->rate = clk->parent->rate / md_table[idx];
+       return clk->parent->rate / md_table[idx];
 }
 
 static struct clk_ops sh7710_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FRQCR) & 0x0700) >> 8;
-       clk->rate = clk->parent->rate / md_table[idx];
+       return clk->parent->rate / md_table[idx];
 }
 
 static struct clk_ops sh7710_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
+static unsigned long cpu_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FRQCR) & 0x0070) >> 4;
-       clk->rate = clk->parent->rate / md_table[idx];
+       return clk->parent->rate / md_table[idx];
 }
 
 static struct clk_ops sh7710_cpu_clk_ops = {
index 54f54df51ef0e4eb08b6adcd62836222f8ed6627..6428ee6c77edc4c028d5b6ecd21437993a92ce8b 100644 (file)
@@ -33,24 +33,24 @@ static struct clk_ops sh7712_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int frqcr = ctrl_inw(FRQCR);
        int idx = frqcr & 0x0007;
 
-       clk->rate = clk->parent->rate / divisors[idx];
+       return clk->parent->rate / divisors[idx];
 }
 
 static struct clk_ops sh7712_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
+static unsigned long cpu_clk_recalc(struct clk *clk)
 {
        int frqcr = ctrl_inw(FRQCR);
        int idx = (frqcr & 0x0030) >> 4;
 
-       clk->rate = clk->parent->rate / divisors[idx];
+       return clk->parent->rate / divisors[idx];
 }
 
 static struct clk_ops sh7712_cpu_clk_ops = {
index 63b67badd67e630ded46a1ccbfa59afc607fe635..88f742fed9edf445269743a6f5198c656ebc9117 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/irq.h>
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
 #include <asm/rtc.h>
 
 enum {
@@ -116,7 +117,102 @@ static struct platform_device rtc_device = {
        },
 };
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x02,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xfffffe94,
+               .end    = 0xfffffe9f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0xe,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xfffffea0,
+               .end    = 0xfffffeab,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1a,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xfffffeac,
+               .end    = 0xfffffebb,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
 static struct platform_device *sh7705_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
        &sci_device,
        &rtc_device,
 };
@@ -128,6 +224,18 @@ static int __init sh7705_devices_setup(void)
 }
 __initcall(sh7705_devices_setup);
 
+static struct platform_device *sh7705_early_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7705_early_devices,
+                                  ARRAY_SIZE(sh7705_early_devices));
+}
+
 void __init plat_irq_setup(void)
 {
        register_intc_controller(&intc_desc);
index a74f960b5e79a5df1aa578a1e30fc4bbfe0a1590..c56306798584f68989ab9d5c82c89071141122e1 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/platform_device.h>
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
 
 enum {
        UNUSED = 0,
@@ -144,7 +145,102 @@ static struct platform_device sci_device = {
        },
 };
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x02,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xfffffe94,
+               .end    = 0xfffffe9f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0xe,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xfffffea0,
+               .end    = 0xfffffeab,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1a,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xfffffeac,
+               .end    = 0xfffffebb,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
 static struct platform_device *sh770x_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
        &sci_device,
        &rtc_device,
 };
@@ -156,6 +252,18 @@ static int __init sh770x_devices_setup(void)
 }
 __initcall(sh770x_devices_setup);
 
+static struct platform_device *sh770x_early_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh770x_early_devices,
+                                  ARRAY_SIZE(sh770x_early_devices));
+}
+
 void __init plat_irq_setup(void)
 {
        register_intc_controller(&intc_desc);
index 335098b66e2f6771a3934aa5babc08adc35dc552..efa76c8148f4e4d2ab7807852d07c3aa5e3cc918 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/irq.h>
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
 #include <asm/rtc.h>
 
 enum {
@@ -120,7 +121,102 @@ static struct platform_device sci_device = {
        },
 };
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x02,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xa412fe94,
+               .end    = 0xa412fe9f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0xe,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xa412fea0,
+               .end    = 0xa412feab,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1a,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xa412feac,
+               .end    = 0xa412feb5,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
 static struct platform_device *sh7710_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
        &sci_device,
        &rtc_device,
 };
@@ -132,6 +228,18 @@ static int __init sh7710_devices_setup(void)
 }
 __initcall(sh7710_devices_setup);
 
+static struct platform_device *sh7710_early_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7710_early_devices,
+                                  ARRAY_SIZE(sh7710_early_devices));
+}
+
 void __init plat_irq_setup(void)
 {
        register_intc_controller(&intc_desc);
index 003874a2fd2a1b191303d91f5708966e286380a1..5b2107798edbe3fc804a19940c63def3e0dc850b 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/serial.h>
 #include <linux/io.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
 #include <asm/rtc.h>
 
 static struct resource rtc_resources[] = {
@@ -123,7 +124,259 @@ static struct platform_device usbf_device = {
        .resource       = usbf_resources,
 };
 
+static struct sh_timer_config cmt0_platform_data = {
+       .name = "CMT0",
+       .channel_offset = 0x10,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 125,
+       .clocksource_rating = 125,
+};
+
+static struct resource cmt0_resources[] = {
+       [0] = {
+               .name   = "CMT0",
+               .start  = 0x044a0010,
+               .end    = 0x044a001b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 104,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt0_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt0_platform_data,
+       },
+       .resource       = cmt0_resources,
+       .num_resources  = ARRAY_SIZE(cmt0_resources),
+};
+
+static struct sh_timer_config cmt1_platform_data = {
+       .name = "CMT1",
+       .channel_offset = 0x20,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+};
+
+static struct resource cmt1_resources[] = {
+       [0] = {
+               .name   = "CMT1",
+               .start  = 0x044a0020,
+               .end    = 0x044a002b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 104,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt1_device = {
+       .name           = "sh_cmt",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &cmt1_platform_data,
+       },
+       .resource       = cmt1_resources,
+       .num_resources  = ARRAY_SIZE(cmt1_resources),
+};
+
+static struct sh_timer_config cmt2_platform_data = {
+       .name = "CMT2",
+       .channel_offset = 0x30,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource cmt2_resources[] = {
+       [0] = {
+               .name   = "CMT2",
+               .start  = 0x044a0030,
+               .end    = 0x044a003b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 104,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt2_device = {
+       .name           = "sh_cmt",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &cmt2_platform_data,
+       },
+       .resource       = cmt2_resources,
+       .num_resources  = ARRAY_SIZE(cmt2_resources),
+};
+
+static struct sh_timer_config cmt3_platform_data = {
+       .name = "CMT3",
+       .channel_offset = 0x40,
+       .timer_bit = 3,
+       .clk = "peripheral_clk",
+};
+
+static struct resource cmt3_resources[] = {
+       [0] = {
+               .name   = "CMT3",
+               .start  = 0x044a0040,
+               .end    = 0x044a004b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 104,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt3_device = {
+       .name           = "sh_cmt",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &cmt3_platform_data,
+       },
+       .resource       = cmt3_resources,
+       .num_resources  = ARRAY_SIZE(cmt3_resources),
+};
+
+static struct sh_timer_config cmt4_platform_data = {
+       .name = "CMT4",
+       .channel_offset = 0x50,
+       .timer_bit = 4,
+       .clk = "peripheral_clk",
+};
+
+static struct resource cmt4_resources[] = {
+       [0] = {
+               .name   = "CMT4",
+               .start  = 0x044a0050,
+               .end    = 0x044a005b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 104,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt4_device = {
+       .name           = "sh_cmt",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &cmt4_platform_data,
+       },
+       .resource       = cmt4_resources,
+       .num_resources  = ARRAY_SIZE(cmt4_resources),
+};
+
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x02,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xa412fe94,
+               .end    = 0xa412fe9f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0xe,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xa412fea0,
+               .end    = 0xa412feab,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1a,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xa412feac,
+               .end    = 0xa412feb5,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
 static struct platform_device *sh7720_devices[] __initdata = {
+       &cmt0_device,
+       &cmt1_device,
+       &cmt2_device,
+       &cmt3_device,
+       &cmt4_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
        &rtc_device,
        &sci_device,
        &usb_ohci_device,
@@ -137,6 +390,23 @@ static int __init sh7720_devices_setup(void)
 }
 __initcall(sh7720_devices_setup);
 
+static struct platform_device *sh7720_early_devices[] __initdata = {
+       &cmt0_device,
+       &cmt1_device,
+       &cmt2_device,
+       &cmt3_device,
+       &cmt4_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7720_early_devices,
+                                  ARRAY_SIZE(sh7720_early_devices));
+}
+
 enum {
        UNUSED = 0,
 
index a33429463e96cd0c758b9f05f631a5d610025d6e..21421e34e7d5b92d2610b840dc59c201efbf6faa 100644 (file)
 static int frqcr3_divisors[] = { 1, 2, 3, 4, 6, 8, 16 };
 static int frqcr3_values[]   = { 0, 1, 2, 3, 4, 5, 6  };
 
-static void emi_clk_recalc(struct clk *clk)
+static unsigned long emi_clk_recalc(struct clk *clk)
 {
        int idx = ctrl_inl(CPG2_FRQCR3) & 0x0007;
-       clk->rate = clk->parent->rate / frqcr3_divisors[idx];
+       return clk->parent->rate / frqcr3_divisors[idx];
 }
 
 static inline int frqcr3_lookup(struct clk *clk, unsigned long rate)
@@ -46,14 +46,14 @@ static struct clk_ops sh4202_emi_clk_ops = {
 
 static struct clk sh4202_emi_clk = {
        .name           = "emi_clk",
-       .flags          = CLK_ALWAYS_ENABLED,
+       .flags          = CLK_ENABLE_ON_INIT,
        .ops            = &sh4202_emi_clk_ops,
 };
 
-static void femi_clk_recalc(struct clk *clk)
+static unsigned long femi_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inl(CPG2_FRQCR3) >> 3) & 0x0007;
-       clk->rate = clk->parent->rate / frqcr3_divisors[idx];
+       return clk->parent->rate / frqcr3_divisors[idx];
 }
 
 static struct clk_ops sh4202_femi_clk_ops = {
@@ -62,7 +62,7 @@ static struct clk_ops sh4202_femi_clk_ops = {
 
 static struct clk sh4202_femi_clk = {
        .name           = "femi_clk",
-       .flags          = CLK_ALWAYS_ENABLED,
+       .flags          = CLK_ENABLE_ON_INIT,
        .ops            = &sh4202_femi_clk_ops,
 };
 
@@ -90,10 +90,10 @@ static void shoc_clk_init(struct clk *clk)
        WARN_ON(i == ARRAY_SIZE(frqcr3_divisors));      /* Undefined clock */
 }
 
-static void shoc_clk_recalc(struct clk *clk)
+static unsigned long shoc_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inl(CPG2_FRQCR3) >> 6) & 0x0007;
-       clk->rate = clk->parent->rate / frqcr3_divisors[idx];
+       return clk->parent->rate / frqcr3_divisors[idx];
 }
 
 static int shoc_clk_verify_rate(struct clk *clk, unsigned long rate)
@@ -140,7 +140,7 @@ static struct clk_ops sh4202_shoc_clk_ops = {
 
 static struct clk sh4202_shoc_clk = {
        .name           = "shoc_clk",
-       .flags          = CLK_ALWAYS_ENABLED,
+       .flags          = CLK_ENABLE_ON_INIT,
        .ops            = &sh4202_shoc_clk_ops,
 };
 
@@ -150,31 +150,22 @@ static struct clk *sh4202_onchip_clocks[] = {
        &sh4202_shoc_clk,
 };
 
-static int __init sh4202_clk_init(void)
+int __init arch_clk_init(void)
 {
-       struct clk *clk = clk_get(NULL, "master_clk");
-       int i;
+       struct clk *clk;
+       int i, ret = 0;
+
+       cpg_clk_init();
 
+       clk = clk_get(NULL, "master_clk");
        for (i = 0; i < ARRAY_SIZE(sh4202_onchip_clocks); i++) {
                struct clk *clkp = sh4202_onchip_clocks[i];
 
                clkp->parent = clk;
-               clk_register(clkp);
-               clk_enable(clkp);
+               ret |= clk_register(clkp);
        }
 
-       /*
-        * Now that we have the rest of the clocks registered, we need to
-        * force the parent clock to propagate so that these clocks will
-        * automatically figure out their rate. We cheat by handing the
-        * parent clock its current rate and forcing child propagation.
-        */
-       clk_set_rate(clk, clk_get_rate(clk));
-
        clk_put(clk);
 
-       return 0;
+       return ret;
 }
-
-arch_initcall(sh4202_clk_init);
-
index dca9f87a12d68fa114cdc6bdbcc252e4caf722c3..73294d9cd0492fe69637be663e3c22a72f21eef2 100644 (file)
@@ -35,30 +35,30 @@ static struct clk_ops sh4_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FRQCR) & 0x0007);
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
+       return clk->parent->rate / pfc_divisors[idx];
 }
 
 static struct clk_ops sh4_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FRQCR) >> 3) & 0x0007;
-       clk->rate = clk->parent->rate / bfc_divisors[idx];
+       return clk->parent->rate / bfc_divisors[idx];
 }
 
 static struct clk_ops sh4_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
+static unsigned long cpu_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(FRQCR) >> 6) & 0x0007;
-       clk->rate = clk->parent->rate / ifc_divisors[idx];
+       return clk->parent->rate / ifc_divisors[idx];
 }
 
 static struct clk_ops sh4_cpu_clk_ops = {
index 91e3677ae09da73b39881c318af163bc5acb2a99..6c78d0a9c857ba2e8e8fef19f3ae89ff6e670209 100644 (file)
@@ -60,12 +60,18 @@ int __init detect_cpu_and_cache_system(void)
                if ((cvr & 0x10000000) == 0)
                        boot_cpu_data.flags |= CPU_HAS_DSP;
 
-               boot_cpu_data.flags |= CPU_HAS_LLSC;
+               boot_cpu_data.flags |= CPU_HAS_LLSC | CPU_HAS_PERF_COUNTER;
                boot_cpu_data.cut_major = pvr & 0x7f;
+
+               boot_cpu_data.icache.ways = 4;
+               boot_cpu_data.dcache.ways = 4;
+       } else {
+               /* And some SH-4 defaults.. */
+               boot_cpu_data.flags |= CPU_HAS_PTEA;
        }
 
        /* FPU detection works for everyone */
-       if ((cvr & 0x20000000) == 1)
+       if ((cvr & 0x20000000))
                boot_cpu_data.flags |= CPU_HAS_FPU;
 
        /* Mask off the upper chip ID */
@@ -78,25 +84,20 @@ int __init detect_cpu_and_cache_system(void)
        switch (pvr) {
        case 0x205:
                boot_cpu_data.type = CPU_SH7750;
-               boot_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
-                                  CPU_HAS_PERF_COUNTER;
+               boot_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG |
+                                      CPU_HAS_PERF_COUNTER;
                break;
        case 0x206:
                boot_cpu_data.type = CPU_SH7750S;
-               boot_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
-                                  CPU_HAS_PERF_COUNTER;
+               boot_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG |
+                                      CPU_HAS_PERF_COUNTER;
                break;
        case 0x1100:
                boot_cpu_data.type = CPU_SH7751;
-               boot_cpu_data.flags |= CPU_HAS_FPU;
                break;
        case 0x2001:
        case 0x2004:
                boot_cpu_data.type = CPU_SH7770;
-               boot_cpu_data.icache.ways = 4;
-               boot_cpu_data.dcache.ways = 4;
-
-               boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_LLSC;
                break;
        case 0x2006:
        case 0x200A:
@@ -107,45 +108,26 @@ int __init detect_cpu_and_cache_system(void)
                else
                        boot_cpu_data.type = CPU_SH7780;
 
-               boot_cpu_data.icache.ways = 4;
-               boot_cpu_data.dcache.ways = 4;
-
-               boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
-                                  CPU_HAS_LLSC;
                break;
        case 0x3000:
        case 0x3003:
        case 0x3009:
                boot_cpu_data.type = CPU_SH7343;
-               boot_cpu_data.icache.ways = 4;
-               boot_cpu_data.dcache.ways = 4;
-               boot_cpu_data.flags |= CPU_HAS_LLSC;
                break;
        case 0x3004:
        case 0x3007:
                boot_cpu_data.type = CPU_SH7785;
-               boot_cpu_data.icache.ways = 4;
-               boot_cpu_data.dcache.ways = 4;
-               boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
-                                         CPU_HAS_LLSC;
                break;
        case 0x4004:
                boot_cpu_data.type = CPU_SH7786;
-               boot_cpu_data.icache.ways = 4;
-               boot_cpu_data.dcache.ways = 4;
-               boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
-                       CPU_HAS_LLSC | CPU_HAS_PTEAEX;
+               boot_cpu_data.flags |= CPU_HAS_PTEAEX | CPU_HAS_L2_CACHE;
                break;
        case 0x3008:
-               boot_cpu_data.icache.ways = 4;
-               boot_cpu_data.dcache.ways = 4;
-               boot_cpu_data.flags |= CPU_HAS_LLSC;
-
                switch (prr) {
                case 0x50:
                case 0x51:
                        boot_cpu_data.type = CPU_SH7723;
-                       boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_L2_CACHE;
+                       boot_cpu_data.flags |= CPU_HAS_L2_CACHE;
                        break;
                case 0x70:
                        boot_cpu_data.type = CPU_SH7366;
@@ -156,13 +138,13 @@ int __init detect_cpu_and_cache_system(void)
                        break;
                }
                break;
+       case 0x300b:
+               boot_cpu_data.type = CPU_SH7724;
+               boot_cpu_data.flags |= CPU_HAS_L2_CACHE;
+               break;
        case 0x4000:    /* 1st cut */
        case 0x4001:    /* 2nd cut */
                boot_cpu_data.type = CPU_SHX3;
-               boot_cpu_data.icache.ways = 4;
-               boot_cpu_data.dcache.ways = 4;
-               boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
-                                         CPU_HAS_LLSC;
                break;
        case 0x700:
                boot_cpu_data.type = CPU_SH4_501;
@@ -173,7 +155,6 @@ int __init detect_cpu_and_cache_system(void)
                boot_cpu_data.type = CPU_SH4_202;
                boot_cpu_data.icache.ways = 2;
                boot_cpu_data.dcache.ways = 2;
-               boot_cpu_data.flags |= CPU_HAS_FPU;
                break;
        case 0x500 ... 0x501:
                switch (prr) {
@@ -191,18 +172,12 @@ int __init detect_cpu_and_cache_system(void)
                boot_cpu_data.icache.ways = 2;
                boot_cpu_data.dcache.ways = 2;
 
-               boot_cpu_data.flags |= CPU_HAS_FPU;
-
                break;
        default:
                boot_cpu_data.type = CPU_SH_NONE;
                break;
        }
 
-#ifdef CONFIG_CPU_HAS_PTEA
-       boot_cpu_data.flags |= CPU_HAS_PTEA;
-#endif
-
        /*
         * On anything that's not a direct-mapped cache, look to the CVR
         * for I/D-cache specifics.
@@ -222,43 +197,48 @@ int __init detect_cpu_and_cache_system(void)
        }
 
        /*
-        * Setup the L2 cache desc
-        *
         * SH-4A's have an optional PIPT L2.
         */
        if (boot_cpu_data.flags & CPU_HAS_L2_CACHE) {
-               /* Bug if we can't decode the L2 info */
-               BUG_ON(!(cvr & 0xf));
-
-               /* Silicon and specifications have clearly never met.. */
-               cvr ^= 0xf;
-
                /*
-                * Size calculation is much more sensible
-                * than it is for the L1.
-                *
-                * Sizes are 128KB, 258KB, 512KB, and 1MB.
+                * Verify that it really has something hooked up, this
+                * is the safety net for CPUs that have optional L2
+                * support yet do not implement it.
                 */
-               size = (cvr & 0xf) << 17;
-
-               BUG_ON(!size);
-
-               boot_cpu_data.scache.way_incr           = (1 << 16);
-               boot_cpu_data.scache.entry_shift        = 5;
-               boot_cpu_data.scache.ways               = 4;
-               boot_cpu_data.scache.linesz             = L1_CACHE_BYTES;
-
-               boot_cpu_data.scache.entry_mask =
-                       (boot_cpu_data.scache.way_incr -
-                        boot_cpu_data.scache.linesz);
-
-               boot_cpu_data.scache.sets       = size /
-                       (boot_cpu_data.scache.linesz *
-                        boot_cpu_data.scache.ways);
-
-               boot_cpu_data.scache.way_size   =
-                       (boot_cpu_data.scache.sets *
-                        boot_cpu_data.scache.linesz);
+               if ((cvr & 0xf) == 0)
+                       boot_cpu_data.flags &= ~CPU_HAS_L2_CACHE;
+               else {
+                       /*
+                        * Silicon and specifications have clearly never
+                        * met..
+                        */
+                       cvr ^= 0xf;
+
+                       /*
+                        * Size calculation is much more sensible
+                        * than it is for the L1.
+                        *
+                        * Sizes are 128KB, 258KB, 512KB, and 1MB.
+                        */
+                       size = (cvr & 0xf) << 17;
+
+                       boot_cpu_data.scache.way_incr           = (1 << 16);
+                       boot_cpu_data.scache.entry_shift        = 5;
+                       boot_cpu_data.scache.ways               = 4;
+                       boot_cpu_data.scache.linesz             = L1_CACHE_BYTES;
+
+                       boot_cpu_data.scache.entry_mask =
+                               (boot_cpu_data.scache.way_incr -
+                                boot_cpu_data.scache.linesz);
+
+                       boot_cpu_data.scache.sets       = size /
+                               (boot_cpu_data.scache.linesz *
+                                boot_cpu_data.scache.ways);
+
+                       boot_cpu_data.scache.way_size   =
+                               (boot_cpu_data.scache.sets *
+                                boot_cpu_data.scache.linesz);
+               }
        }
 
        return 0;
index 7371abf64f8082a902fefc675aec6579ec73b1ac..6d088d12359172f8b8b9d9e99ee3162ad46f06a5 100644 (file)
@@ -2,6 +2,7 @@
  * SH4-202 Setup
  *
  *  Copyright (C) 2006  Paul Mundt
+ *  Copyright (C) 2009  Magnus Damm
  *
  * 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
@@ -11,6 +12,8 @@
 #include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
 
 static struct plat_sci_port sci_platform_data[] = {
        {
@@ -31,8 +34,103 @@ static struct platform_device sci_device = {
        },
 };
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xffd80008,
+               .end    = 0xffd80013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xffd80014,
+               .end    = 0xffd8001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xffd80020,
+               .end    = 0xffd8002f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
 static struct platform_device *sh4202_devices[] __initdata = {
        &sci_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
 };
 
 static int __init sh4202_devices_setup(void)
@@ -42,7 +140,71 @@ static int __init sh4202_devices_setup(void)
 }
 __initcall(sh4202_devices_setup);
 
+static struct platform_device *sh4202_early_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh4202_early_devices,
+                                  ARRAY_SIZE(sh4202_early_devices));
+}
+
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       IRL0, IRL1, IRL2, IRL3, /* only IRLM mode supported */
+       HUDI, TMU0, TMU1, TMU2, RTC, SCIF, WDT,
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_VECT(HUDI, 0x600),
+       INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+       INTC_VECT(TMU2, 0x440), INTC_VECT(TMU2, 0x460),
+       INTC_VECT(RTC, 0x480), INTC_VECT(RTC, 0x4a0),
+       INTC_VECT(RTC, 0x4c0),
+       INTC_VECT(SCIF, 0x700), INTC_VECT(SCIF, 0x720),
+       INTC_VECT(SCIF, 0x740), INTC_VECT(SCIF, 0x760),
+       INTC_VECT(WDT, 0x560),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+       { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, 0, 0, 0 } },
+       { 0xffd0000c, 0, 16, 4, /* IPRC */ { 0, 0, SCIF, HUDI } },
+       { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh4-202", vectors, NULL,
+                        NULL, prio_registers, NULL);
+
+static struct intc_vect vectors_irlm[] __initdata = {
+       INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
+       INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irlm, "sh4-202_irlm", vectors_irlm, NULL,
+                        NULL, prio_registers, NULL);
+
 void __init plat_irq_setup(void)
 {
-       /* do nothing - all IRL interrupts are handled by the board code */
+       register_intc_controller(&intc_desc);
+}
+
+#define INTC_ICR       0xffd00000UL
+#define INTC_ICR_IRLM   (1<<7)
+
+void __init plat_irq_setup_pins(int mode)
+{
+       switch (mode) {
+       case IRQ_MODE_IRQ: /* individual interrupt mode for IRL3-0 */
+               ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
+               register_intc_controller(&intc_desc_irlm);
+               break;
+       default:
+               BUG();
+       }
 }
index a1c80d909cd634c1b8a2459c5d239fa600c8285b..851672d15cf4a15e5f3b2208681417a269d1ba99 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/io.h>
+#include <linux/sh_timer.h>
 #include <linux/serial_sci.h>
 
 static struct resource rtc_resources[] = {
@@ -60,9 +61,177 @@ static struct platform_device sci_device = {
        },
 };
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xffd80008,
+               .end    = 0xffd80013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xffd80014,
+               .end    = 0xffd8001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xffd80020,
+               .end    = 0xffd8002f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
+/* SH7750R, SH7751 and SH7751R all have two extra timer channels */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751R)
+
+static struct sh_timer_config tmu3_platform_data = {
+       .name = "TMU3",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu3_resources[] = {
+       [0] = {
+               .name   = "TMU3",
+               .start  = 0xfe100008,
+               .end    = 0xfe100013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 72,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu3_device = {
+       .name           = "sh_tmu",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &tmu3_platform_data,
+       },
+       .resource       = tmu3_resources,
+       .num_resources  = ARRAY_SIZE(tmu3_resources),
+};
+
+static struct sh_timer_config tmu4_platform_data = {
+       .name = "TMU4",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu4_resources[] = {
+       [0] = {
+               .name   = "TMU4",
+               .start  = 0xfe100014,
+               .end    = 0xfe10001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 76,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu4_device = {
+       .name           = "sh_tmu",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &tmu4_platform_data,
+       },
+       .resource       = tmu4_resources,
+       .num_resources  = ARRAY_SIZE(tmu4_resources),
+};
+
+#endif
+
 static struct platform_device *sh7750_devices[] __initdata = {
        &rtc_device,
        &sci_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751R)
+       &tmu3_device,
+       &tmu4_device,
+#endif
 };
 
 static int __init sh7750_devices_setup(void)
@@ -72,6 +241,24 @@ static int __init sh7750_devices_setup(void)
 }
 __initcall(sh7750_devices_setup);
 
+static struct platform_device *sh7750_early_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751R)
+       &tmu3_device,
+       &tmu4_device,
+#endif
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7750_early_devices,
+                                  ARRAY_SIZE(sh7750_early_devices));
+}
+
 enum {
        UNUSED = 0,
 
index d9bdc931ac09138f84b007fc3d0f9ff92f5f900e..5b822519bd90cb7593b74338b9442adc734caab9 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/platform_device.h>
 #include <linux/init.h>
 #include <linux/serial.h>
+#include <linux/sh_timer.h>
 #include <linux/serial_sci.h>
 #include <linux/io.h>
 
@@ -18,10 +19,7 @@ enum {
 
        /* interrupt sources */
        IRL0, IRL1, IRL2, IRL3,
-       HUDI, GPIOI,
-       DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3,
-       DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7,
-       DMAC_DMAE,
+       HUDI, GPIOI, DMAC,
        IRQ4, IRQ5, IRQ6, IRQ7,
        HCAN20, HCAN21,
        SSI0, SSI1,
@@ -36,21 +34,20 @@ enum {
        HSPI,
        MMCIF0, MMCIF1, MMCIF2, MMCIF3,
        MFI, ADC, CMT,
-       TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
-       WDT,
-       REF_RCMI, REF_ROVI,
+       TMU0, TMU1, TMU2,
+       WDT, REF,
 
        /* interrupt groups */
-       DMAC, DMABRG, SCIF0, SCIF1, SCIF2, SIM, MMCIF, TMU2, REF,
+       DMABRG, SCIF0, SCIF1, SCIF2, SIM, MMCIF,
 };
 
 static struct intc_vect vectors[] __initdata = {
        INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
-       INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
-       INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
-       INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0),
-       INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0),
-       INTC_VECT(DMAC_DMAE, 0x6c0),
+       INTC_VECT(DMAC, 0x640), INTC_VECT(DMAC, 0x660),
+       INTC_VECT(DMAC, 0x680), INTC_VECT(DMAC, 0x6a0),
+       INTC_VECT(DMAC, 0x780), INTC_VECT(DMAC, 0x7a0),
+       INTC_VECT(DMAC, 0x7c0), INTC_VECT(DMAC, 0x7e0),
+       INTC_VECT(DMAC, 0x6c0),
        INTC_VECT(IRQ4, 0x800), INTC_VECT(IRQ5, 0x820),
        INTC_VECT(IRQ6, 0x840), INTC_VECT(IRQ6, 0x860),
        INTC_VECT(HCAN20, 0x900), INTC_VECT(HCAN21, 0x920),
@@ -74,23 +71,18 @@ static struct intc_vect vectors[] __initdata = {
        INTC_VECT(MFI, 0xe80), /* 0xf80 according to data sheet */
        INTC_VECT(ADC, 0xf80), INTC_VECT(CMT, 0xfa0),
        INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
-       INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
+       INTC_VECT(TMU2, 0x440), INTC_VECT(TMU2, 0x460),
        INTC_VECT(WDT, 0x560),
-       INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0),
+       INTC_VECT(REF, 0x580), INTC_VECT(REF, 0x5a0),
 };
 
 static struct intc_group groups[] __initdata = {
-       INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
-                  DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5,
-                  DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE),
        INTC_GROUP(DMABRG, DMABRG0, DMABRG1, DMABRG2),
        INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
        INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
        INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
        INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI),
        INTC_GROUP(MMCIF, MMCIF0, MMCIF1, MMCIF2, MMCIF3),
-       INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
-       INTC_GROUP(REF, REF_RCMI, REF_ROVI),
 };
 
 static struct intc_mask_reg mask_registers[] __initdata = {
@@ -168,8 +160,104 @@ static struct platform_device sci_device = {
        },
 };
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xffd80008,
+               .end    = 0xffd80013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xffd80014,
+               .end    = 0xffd8001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xffd80020,
+               .end    = 0xffd8002f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
+
 static struct platform_device *sh7760_devices[] __initdata = {
        &sci_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
 };
 
 static int __init sh7760_devices_setup(void)
@@ -179,6 +267,18 @@ static int __init sh7760_devices_setup(void)
 }
 __initcall(sh7760_devices_setup);
 
+static struct platform_device *sh7760_early_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7760_early_devices,
+                                  ARRAY_SIZE(sh7760_early_devices));
+}
+
 #define INTC_ICR       0xffd00000UL
 #define INTC_ICR_IRLM  (1 << 7)
 
index 1a92361feeb9db95e50e4f97d5d06a076a66f28e..96ea09ca8cc11d57cd44e3748a61cbc655de94b7 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7786)      += setup-sh7786.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7343)       += setup-sh7343.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7722)       += setup-sh7722.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7723)       += setup-sh7723.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7724)       += setup-sh7724.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7366)       += setup-sh7366.o
 obj-$(CONFIG_CPU_SUBTYPE_SHX3)         += setup-shx3.o
 
@@ -23,15 +24,17 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7770)  := clock-sh7770.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7780)     := clock-sh7780.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7785)     := clock-sh7785.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7786)     := clock-sh7786.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7343)     := clock-sh7722.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7343)     := clock-sh7343.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7722)     := clock-sh7722.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7723)     := clock-sh7722.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7366)     := clock-sh7722.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7723)     := clock-sh7723.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7724)     := clock-sh7724.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7366)     := clock-sh7366.o
 clock-$(CONFIG_CPU_SUBTYPE_SHX3)       := clock-shx3.o
 
 # Pinmux setup
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7722)    := pinmux-sh7722.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7723)    := pinmux-sh7723.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SH7724)    := pinmux-sh7724.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7785)    := pinmux-sh7785.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7786)    := pinmux-sh7786.o
 
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
new file mode 100644 (file)
index 0000000..0ee3ee8
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7343.c
+ *
+ * SH7343 clock framework support
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * 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
+ *
+ * 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 <linux/kernel.h>
+#include <linux/io.h>
+#include <asm/clock.h>
+
+/* SH7343 registers */
+#define FRQCR          0xa4150000
+#define VCLKCR         0xa4150004
+#define SCLKACR                0xa4150008
+#define SCLKBCR                0xa415000c
+#define PLLCR          0xa4150024
+#define MSTPCR0                0xa4150030
+#define MSTPCR1                0xa4150034
+#define MSTPCR2                0xa4150038
+#define DLLFRQ         0xa4150050
+
+/* Fixed 32 KHz root clock for RTC and Power Management purposes */
+static struct clk r_clk = {
+       .name           = "rclk",
+       .id             = -1,
+       .rate           = 32768,
+};
+
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+struct clk extal_clk = {
+       .name           = "extal",
+       .id             = -1,
+       .rate           = 33333333,
+};
+
+/* The dll block multiplies the 32khz r_clk, may be used instead of extal */
+static unsigned long dll_recalc(struct clk *clk)
+{
+       unsigned long mult;
+
+       if (__raw_readl(PLLCR) & 0x1000)
+               mult = __raw_readl(DLLFRQ);
+       else
+               mult = 0;
+
+       return clk->parent->rate * mult;
+}
+
+static struct clk_ops dll_clk_ops = {
+       .recalc         = dll_recalc,
+};
+
+static struct clk dll_clk = {
+       .name           = "dll_clk",
+       .id             = -1,
+       .ops            = &dll_clk_ops,
+       .parent         = &r_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+static unsigned long pll_recalc(struct clk *clk)
+{
+       unsigned long mult = 1;
+
+       if (__raw_readl(PLLCR) & 0x4000)
+               mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1);
+
+       return clk->parent->rate * mult;
+}
+
+static struct clk_ops pll_clk_ops = {
+       .recalc         = pll_recalc,
+};
+
+static struct clk pll_clk = {
+       .name           = "pll_clk",
+       .id             = -1,
+       .ops            = &pll_clk_ops,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+struct clk *main_clks[] = {
+       &r_clk,
+       &extal_clk,
+       &dll_clk,
+       &pll_clk,
+};
+
+static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
+
+static struct clk_div_mult_table div4_table = {
+       .divisors = divisors,
+       .nr_divisors = ARRAY_SIZE(divisors),
+       .multipliers = multipliers,
+       .nr_multipliers = ARRAY_SIZE(multipliers),
+};
+
+enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P,
+       DIV4_SIUA, DIV4_SIUB, DIV4_NR };
+
+#define DIV4(_str, _reg, _bit, _mask, _flags) \
+  SH_CLK_DIV4(_str, &pll_clk, _reg, _bit, _mask, _flags)
+
+struct clk div4_clks[DIV4_NR] = {
+       [DIV4_I] = DIV4("cpu_clk", FRQCR, 20, 0x1fff, CLK_ENABLE_ON_INIT),
+       [DIV4_U] = DIV4("umem_clk", FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT),
+       [DIV4_SH] = DIV4("shyway_clk", FRQCR, 12, 0x1fff, CLK_ENABLE_ON_INIT),
+       [DIV4_B] = DIV4("bus_clk", FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT),
+       [DIV4_B3] = DIV4("b3_clk", FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT),
+       [DIV4_P] = DIV4("peripheral_clk", FRQCR, 0, 0x1fff, 0),
+       [DIV4_SIUA] = DIV4("siua_clk", SCLKACR, 0, 0x1fff, 0),
+       [DIV4_SIUB] = DIV4("siub_clk", SCLKBCR, 0, 0x1fff, 0),
+};
+
+struct clk div6_clks[] = {
+       SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0),
+};
+
+#define MSTP(_str, _parent, _reg, _bit, _flags) \
+  SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _flags)
+
+static struct clk mstp_clks[] = {
+       MSTP("tlb0", &div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT),
+       MSTP("ic0", &div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT),
+       MSTP("oc0", &div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT),
+       MSTP("uram0", &div4_clks[DIV4_U], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
+       MSTP("xymem0", &div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
+       MSTP("intc3", &div4_clks[DIV4_P], MSTPCR0, 23, 0),
+       MSTP("intc0", &div4_clks[DIV4_P], MSTPCR0, 22, 0),
+       MSTP("dmac0", &div4_clks[DIV4_P], MSTPCR0, 21, 0),
+       MSTP("sh0", &div4_clks[DIV4_P], MSTPCR0, 20, 0),
+       MSTP("hudi0", &div4_clks[DIV4_P], MSTPCR0, 19, 0),
+       MSTP("ubc0", &div4_clks[DIV4_P], MSTPCR0, 17, 0),
+       MSTP("tmu0", &div4_clks[DIV4_P], MSTPCR0, 15, 0),
+       MSTP("cmt0", &r_clk, MSTPCR0, 14, 0),
+       MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0),
+       MSTP("mfi0", &div4_clks[DIV4_P], MSTPCR0, 11, 0),
+       MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0),
+       MSTP("scif0", &div4_clks[DIV4_P], MSTPCR0, 7, 0),
+       MSTP("scif1", &div4_clks[DIV4_P], MSTPCR0, 6, 0),
+       MSTP("scif2", &div4_clks[DIV4_P], MSTPCR0, 5, 0),
+       MSTP("scif3", &div4_clks[DIV4_P], MSTPCR0, 4, 0),
+       MSTP("sio0", &div4_clks[DIV4_P], MSTPCR0, 3, 0),
+       MSTP("siof0", &div4_clks[DIV4_P], MSTPCR0, 2, 0),
+       MSTP("siof1", &div4_clks[DIV4_P], MSTPCR0, 1, 0),
+
+       MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0),
+       MSTP("i2c1", &div4_clks[DIV4_P], MSTPCR1, 8, 0),
+
+       MSTP("tpu0", &div4_clks[DIV4_P], MSTPCR2, 25, 0),
+       MSTP("irda0", &div4_clks[DIV4_P], MSTPCR2, 24, 0),
+       MSTP("sdhi0", &div4_clks[DIV4_P], MSTPCR2, 18, 0),
+       MSTP("mmcif0", &div4_clks[DIV4_P], MSTPCR2, 17, 0),
+       MSTP("sim0", &div4_clks[DIV4_P], MSTPCR2, 16, 0),
+       MSTP("keysc0", &r_clk, MSTPCR2, 14, 0),
+       MSTP("tsif0", &div4_clks[DIV4_P], MSTPCR2, 13, 0),
+       MSTP("s3d40", &div4_clks[DIV4_P], MSTPCR2, 12, 0),
+       MSTP("usbf0", &div4_clks[DIV4_P], MSTPCR2, 11, 0),
+       MSTP("siu0", &div4_clks[DIV4_B], MSTPCR2, 8, 0),
+       MSTP("jpu0", &div4_clks[DIV4_B], MSTPCR2, 6, CLK_ENABLE_ON_INIT),
+       MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0),
+       MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0),
+       MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0),
+       MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT),
+       MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT),
+       MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0),
+};
+
+int __init arch_clk_init(void)
+{
+       int k, ret = 0;
+
+       /* autodetect extal or dll configuration */
+       if (__raw_readl(PLLCR) & 0x1000)
+               pll_clk.parent = &dll_clk;
+       else
+               pll_clk.parent = &extal_clk;
+
+       for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+               ret = clk_register(main_clks[k]);
+
+       if (!ret)
+               ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+       if (!ret)
+               ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks));
+
+       if (!ret)
+               ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks));
+
+       return ret;
+}
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7366.c b/arch/sh/kernel/cpu/sh4a/clock-sh7366.c
new file mode 100644 (file)
index 0000000..a95ebab
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7366.c
+ *
+ * SH7366 clock framework support
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * 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
+ *
+ * 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 <linux/kernel.h>
+#include <linux/io.h>
+#include <asm/clock.h>
+
+/* SH7366 registers */
+#define FRQCR          0xa4150000
+#define VCLKCR         0xa4150004
+#define SCLKACR                0xa4150008
+#define SCLKBCR                0xa415000c
+#define PLLCR          0xa4150024
+#define MSTPCR0                0xa4150030
+#define MSTPCR1                0xa4150034
+#define MSTPCR2                0xa4150038
+#define DLLFRQ         0xa4150050
+
+/* Fixed 32 KHz root clock for RTC and Power Management purposes */
+static struct clk r_clk = {
+       .name           = "rclk",
+       .id             = -1,
+       .rate           = 32768,
+};
+
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+struct clk extal_clk = {
+       .name           = "extal",
+       .id             = -1,
+       .rate           = 33333333,
+};
+
+/* The dll block multiplies the 32khz r_clk, may be used instead of extal */
+static unsigned long dll_recalc(struct clk *clk)
+{
+       unsigned long mult;
+
+       if (__raw_readl(PLLCR) & 0x1000)
+               mult = __raw_readl(DLLFRQ);
+       else
+               mult = 0;
+
+       return clk->parent->rate * mult;
+}
+
+static struct clk_ops dll_clk_ops = {
+       .recalc         = dll_recalc,
+};
+
+static struct clk dll_clk = {
+       .name           = "dll_clk",
+       .id             = -1,
+       .ops            = &dll_clk_ops,
+       .parent         = &r_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+static unsigned long pll_recalc(struct clk *clk)
+{
+       unsigned long mult = 1;
+       unsigned long div = 1;
+
+       if (__raw_readl(PLLCR) & 0x4000)
+               mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1);
+       else
+               div = 2;
+
+       return (clk->parent->rate * mult) / div;
+}
+
+static struct clk_ops pll_clk_ops = {
+       .recalc         = pll_recalc,
+};
+
+static struct clk pll_clk = {
+       .name           = "pll_clk",
+       .id             = -1,
+       .ops            = &pll_clk_ops,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+struct clk *main_clks[] = {
+       &r_clk,
+       &extal_clk,
+       &dll_clk,
+       &pll_clk,
+};
+
+static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
+
+static struct clk_div_mult_table div4_table = {
+       .divisors = divisors,
+       .nr_divisors = ARRAY_SIZE(divisors),
+       .multipliers = multipliers,
+       .nr_multipliers = ARRAY_SIZE(multipliers),
+};
+
+enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P,
+       DIV4_SIUA, DIV4_SIUB, DIV4_NR };
+
+#define DIV4(_str, _reg, _bit, _mask, _flags) \
+  SH_CLK_DIV4(_str, &pll_clk, _reg, _bit, _mask, _flags)
+
+struct clk div4_clks[DIV4_NR] = {
+       [DIV4_I] = DIV4("cpu_clk", FRQCR, 20, 0x1fef, CLK_ENABLE_ON_INIT),
+       [DIV4_U] = DIV4("umem_clk", FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT),
+       [DIV4_SH] = DIV4("shyway_clk", FRQCR, 12, 0x1fff, CLK_ENABLE_ON_INIT),
+       [DIV4_B] = DIV4("bus_clk", FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT),
+       [DIV4_B3] = DIV4("b3_clk", FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT),
+       [DIV4_P] = DIV4("peripheral_clk", FRQCR, 0, 0x1fff, 0),
+       [DIV4_SIUA] = DIV4("siua_clk", SCLKACR, 0, 0x1fff, 0),
+       [DIV4_SIUB] = DIV4("siub_clk", SCLKBCR, 0, 0x1fff, 0),
+};
+
+struct clk div6_clks[] = {
+       SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0),
+};
+
+#define MSTP(_str, _parent, _reg, _bit, _flags) \
+  SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _flags)
+
+static struct clk mstp_clks[] = {
+       /* See page 52 of Datasheet V0.40: Overview -> Block Diagram */
+       MSTP("tlb0", &div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT),
+       MSTP("ic0", &div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT),
+       MSTP("oc0", &div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT),
+       MSTP("rsmem0", &div4_clks[DIV4_SH], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
+       MSTP("xymem0", &div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
+       MSTP("intc3", &div4_clks[DIV4_P], MSTPCR0, 23, 0),
+       MSTP("intc0", &div4_clks[DIV4_P], MSTPCR0, 22, 0),
+       MSTP("dmac0", &div4_clks[DIV4_P], MSTPCR0, 21, 0),
+       MSTP("sh0", &div4_clks[DIV4_P], MSTPCR0, 20, 0),
+       MSTP("hudi0", &div4_clks[DIV4_P], MSTPCR0, 19, 0),
+       MSTP("ubc0", &div4_clks[DIV4_P], MSTPCR0, 17, 0),
+       MSTP("tmu0", &div4_clks[DIV4_P], MSTPCR0, 15, 0),
+       MSTP("cmt0", &r_clk, MSTPCR0, 14, 0),
+       MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0),
+       MSTP("mfi0", &div4_clks[DIV4_P], MSTPCR0, 11, 0),
+       MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0),
+       MSTP("scif0", &div4_clks[DIV4_P], MSTPCR0, 7, 0),
+       MSTP("scif1", &div4_clks[DIV4_P], MSTPCR0, 6, 0),
+       MSTP("scif2", &div4_clks[DIV4_P], MSTPCR0, 5, 0),
+       MSTP("msiof0", &div4_clks[DIV4_P], MSTPCR0, 2, 0),
+       MSTP("sbr0", &div4_clks[DIV4_P], MSTPCR0, 1, 0),
+
+       MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0),
+
+       MSTP("icb0", &div4_clks[DIV4_P], MSTPCR2, 27, 0),
+       MSTP("meram0", &div4_clks[DIV4_P], MSTPCR2, 26, 0),
+       MSTP("dacy1", &div4_clks[DIV4_P], MSTPCR2, 24, 0),
+       MSTP("dacy0", &div4_clks[DIV4_P], MSTPCR2, 23, 0),
+       MSTP("tsif0", &div4_clks[DIV4_P], MSTPCR2, 22, 0),
+       MSTP("sdhi0", &div4_clks[DIV4_P], MSTPCR2, 18, 0),
+       MSTP("mmcif0", &div4_clks[DIV4_P], MSTPCR2, 17, 0),
+       MSTP("usbf0", &div4_clks[DIV4_P], MSTPCR2, 11, 0),
+       MSTP("siu0", &div4_clks[DIV4_B], MSTPCR2, 9, 0),
+       MSTP("veu1", &div4_clks[DIV4_B], MSTPCR2, 7, CLK_ENABLE_ON_INIT),
+       MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0),
+       MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0),
+       MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0),
+       MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT),
+       MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT),
+       MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0),
+};
+
+int __init arch_clk_init(void)
+{
+       int k, ret = 0;
+
+       /* autodetect extal or dll configuration */
+       if (__raw_readl(PLLCR) & 0x1000)
+               pll_clk.parent = &dll_clk;
+       else
+               pll_clk.parent = &extal_clk;
+
+       for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+               ret = clk_register(main_clks[k]);
+
+       if (!ret)
+               ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+       if (!ret)
+               ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks));
+
+       if (!ret)
+               ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks));
+
+       return ret;
+}
index 0e174af21874123497614da2e36f0eb0a7e66cfa..40f859354f793507c1a0feb7899f4840570f00b8 100644 (file)
 /*
  * arch/sh/kernel/cpu/sh4a/clock-sh7722.c
  *
- * SH7343, SH7722, SH7723 & SH7366 support for the clock framework
+ * SH7722 clock framework support
  *
- * Copyright (c) 2006-2007 Nomad Global Solutions Inc
- * Based on code for sh7343 by Paul Mundt
+ * Copyright (C) 2009 Magnus Damm
  *
- * 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.
+ * 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
+ *
+ * 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 <linux/kernel.h>
 #include <linux/io.h>
-#include <linux/errno.h>
-#include <linux/stringify.h>
 #include <asm/clock.h>
-#include <asm/freq.h>
-
-#define N  (-1)
-#define NM (-2)
-#define ROUND_NEAREST 0
-#define ROUND_DOWN -1
-#define ROUND_UP   +1
-
-static int adjust_algos[][3] = {
-       {},     /* NO_CHANGE */
-       { NM, N, 1 },   /* N:1, N:1 */
-       { 3, 2, 2 },    /* 3:2:2 */
-       { 5, 2, 2 },    /* 5:2:2 */
-       { N, 1, 1 },    /* N:1:1 */
-
-       { N, 1 },       /* N:1 */
 
-       { N, 1 },       /* N:1 */
-       { 3, 2 },
-       { 4, 3 },
-       { 5, 4 },
-
-       { N, 1 }
+/* SH7722 registers */
+#define FRQCR          0xa4150000
+#define VCLKCR         0xa4150004
+#define SCLKACR                0xa4150008
+#define SCLKBCR                0xa415000c
+#define IRDACLKCR      0xa4150018
+#define PLLCR          0xa4150024
+#define MSTPCR0                0xa4150030
+#define MSTPCR1                0xa4150034
+#define MSTPCR2                0xa4150038
+#define DLLFRQ         0xa4150050
+
+/* Fixed 32 KHz root clock for RTC and Power Management purposes */
+static struct clk r_clk = {
+       .name           = "rclk",
+       .id             = -1,
+       .rate           = 32768,
 };
 
-static unsigned long adjust_pair_of_clocks(unsigned long r1, unsigned long r2,
-                       int m1, int m2, int round_flag)
-{
-       unsigned long rem, div;
-       int the_one = 0;
-
-       pr_debug( "Actual values: r1 = %ld\n", r1);
-       pr_debug( "...............r2 = %ld\n", r2);
-
-       if (m1 == m2) {
-               r2 = r1;
-               pr_debug( "setting equal rates: r2 now %ld\n", r2);
-       } else if ((m2 == N  && m1 == 1) ||
-                  (m2 == NM && m1 == N)) { /* N:1 or NM:N */
-               pr_debug( "Setting rates as 1:N (N:N*M)\n");
-               rem = r2 % r1;
-               pr_debug( "...remainder = %ld\n", rem);
-               if (rem) {
-                       div = r2 / r1;
-                       pr_debug( "...div = %ld\n", div);
-                       switch (round_flag) {
-                       case ROUND_NEAREST:
-                               the_one = rem >= r1/2 ? 1 : 0; break;
-                       case ROUND_UP:
-                               the_one = 1; break;
-                       case ROUND_DOWN:
-                               the_one = 0; break;
-                       }
-
-                       r2 = r1 * (div + the_one);
-                       pr_debug( "...setting r2 to %ld\n", r2);
-               }
-       } else if ((m2 == 1  && m1 == N) ||
-                  (m2 == N && m1 == NM)) { /* 1:N or N:NM */
-               pr_debug( "Setting rates as N:1 (N*M:N)\n");
-               rem = r1 % r2;
-               pr_debug( "...remainder = %ld\n", rem);
-               if (rem) {
-                       div = r1 / r2;
-                       pr_debug( "...div = %ld\n", div);
-                       switch (round_flag) {
-                       case ROUND_NEAREST:
-                               the_one = rem > r2/2 ? 1 : 0; break;
-                       case ROUND_UP:
-                               the_one = 0; break;
-                       case ROUND_DOWN:
-                               the_one = 1; break;
-                       }
-
-                       r2 = r1 / (div + the_one);
-                       pr_debug( "...setting r2 to %ld\n", r2);
-               }
-       } else { /* value:value */
-               pr_debug( "Setting rates as %d:%d\n", m1, m2);
-               div = r1 / m1;
-               r2 = div * m2;
-               pr_debug( "...div = %ld\n", div);
-               pr_debug( "...setting r2 to %ld\n", r2);
-       }
-
-       return r2;
-}
-
-static void adjust_clocks(int originate, int *l, unsigned long v[],
-                         int n_in_line)
-{
-       int x;
-
-       pr_debug( "Go down from %d...\n", originate);
-       /* go up recalculation clocks */
-       for (x = originate; x>0; x -- )
-               v[x-1] = adjust_pair_of_clocks(v[x], v[x-1],
-                                       l[x], l[x-1],
-                                       ROUND_UP);
-
-       pr_debug( "Go up from %d...\n", originate);
-       /* go down recalculation clocks */
-       for (x = originate; x<n_in_line - 1; x ++ )
-               v[x+1] = adjust_pair_of_clocks(v[x], v[x+1],
-                                       l[x], l[x+1],
-                                       ROUND_UP);
-}
-
-
 /*
- * SH7722 uses a common set of multipliers and divisors, so this
- * is quite simple..
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
  */
-
-/*
- * Instead of having two separate multipliers/divisors set, like this:
- *
- * static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
- * static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
- *
- * I created the divisors2 array, which is used to calculate rate like
- *   rate = parent * 2 / divisors2[ divisor ];
-*/
-static int divisors2[] = { 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40 };
-
-static void master_clk_recalc(struct clk *clk)
-{
-       unsigned frqcr = ctrl_inl(FRQCR);
-
-       clk->rate = CONFIG_SH_PCLK_FREQ * (((frqcr >> 24) & 0x1f) + 1);
-}
-
-static void master_clk_init(struct clk *clk)
-{
-       clk->parent = NULL;
-       clk->flags |= CLK_RATE_PROPAGATES;
-       clk->rate = CONFIG_SH_PCLK_FREQ;
-       master_clk_recalc(clk);
-}
-
-
-static void module_clk_recalc(struct clk *clk)
-{
-       unsigned long frqcr = ctrl_inl(FRQCR);
-
-       clk->rate = clk->parent->rate / (((frqcr >> 24) & 0x1f) + 1);
-}
-
-static int master_clk_setrate(struct clk *clk, unsigned long rate, int id)
-{
-       int div = rate / clk->rate;
-       int master_divs[] = { 2, 3, 4, 6, 8, 16 };
-       int index;
-       unsigned long frqcr;
-
-       for (index = 1; index < ARRAY_SIZE(master_divs); index++)
-               if (div >= master_divs[index - 1] && div < master_divs[index])
-                       break;
-
-       if (index >= ARRAY_SIZE(master_divs))
-               index = ARRAY_SIZE(master_divs);
-       div = master_divs[index - 1];
-
-       frqcr = ctrl_inl(FRQCR);
-       frqcr &= ~(0xF << 24);
-       frqcr |= ( (div-1) << 24);
-       ctrl_outl(frqcr, FRQCR);
-
-       return 0;
-}
-
-static struct clk_ops sh7722_master_clk_ops = {
-       .init = master_clk_init,
-       .recalc = master_clk_recalc,
-       .set_rate = master_clk_setrate,
-};
-
-static struct clk_ops sh7722_module_clk_ops = {
-       .recalc = module_clk_recalc,
-};
-
-struct frqcr_context {
-       unsigned mask;
-       unsigned shift;
-};
-
-struct frqcr_context sh7722_get_clk_context(const char *name)
-{
-       struct frqcr_context ctx = { 0, };
-
-       if (!strcmp(name, "peripheral_clk")) {
-               ctx.shift = 0;
-               ctx.mask = 0xF;
-       } else if (!strcmp(name, "sdram_clk")) {
-               ctx.shift = 4;
-               ctx.mask = 0xF;
-       } else if (!strcmp(name, "bus_clk")) {
-               ctx.shift = 8;
-               ctx.mask = 0xF;
-       } else if (!strcmp(name, "sh_clk")) {
-               ctx.shift = 12;
-               ctx.mask = 0xF;
-       } else if (!strcmp(name, "umem_clk")) {
-               ctx.shift = 16;
-               ctx.mask = 0xF;
-       } else if (!strcmp(name, "cpu_clk")) {
-               ctx.shift = 20;
-               ctx.mask = 7;
-       }
-       return ctx;
-}
-
-/**
- * sh7722_find_div_index - find divisor for setting rate
- *
- * All sh7722 clocks use the same set of multipliers/divisors. This function
- * chooses correct divisor to set the rate of clock with parent clock that
- * generates frequency of 'parent_rate'
- *
- * @parent_rate: rate of parent clock
- * @rate: requested rate to be set
- */
-static int sh7722_find_div_index(unsigned long parent_rate, unsigned rate)
-{
-       unsigned div2 = parent_rate * 2 / rate;
-       int index;
-
-       if (rate > parent_rate)
-               return -EINVAL;
-
-       for (index = 1; index < ARRAY_SIZE(divisors2); index++) {
-               if (div2 > divisors2[index - 1] && div2 <= divisors2[index])
-                       break;
-       }
-       if (index >= ARRAY_SIZE(divisors2))
-               index = ARRAY_SIZE(divisors2) - 1;
-       return index;
-}
-
-static void sh7722_frqcr_recalc(struct clk *clk)
-{
-       struct frqcr_context ctx = sh7722_get_clk_context(clk->name);
-       unsigned long frqcr = ctrl_inl(FRQCR);
-       int index;
-
-       index = (frqcr >> ctx.shift) & ctx.mask;
-       clk->rate = clk->parent->rate * 2 / divisors2[index];
-}
-
-static int sh7722_frqcr_set_rate(struct clk *clk, unsigned long rate,
-                                int algo_id)
-{
-       struct frqcr_context ctx = sh7722_get_clk_context(clk->name);
-       unsigned long parent_rate = clk->parent->rate;
-       int div;
-       unsigned long frqcr;
-       int err = 0;
-
-       /* pretty invalid */
-       if (parent_rate < rate)
-               return -EINVAL;
-
-       /* look for multiplier/divisor pair */
-       div = sh7722_find_div_index(parent_rate, rate);
-       if (div<0)
-               return div;
-
-       /* calculate new value of clock rate */
-       clk->rate = parent_rate * 2 / divisors2[div];
-       frqcr = ctrl_inl(FRQCR);
-
-       /* FIXME: adjust as algo_id specifies */
-       if (algo_id != NO_CHANGE) {
-               int originator;
-               char *algo_group_1[] = { "cpu_clk", "umem_clk", "sh_clk" };
-               char *algo_group_2[] = { "sh_clk", "bus_clk" };
-               char *algo_group_3[] = { "sh_clk", "sdram_clk" };
-               char *algo_group_4[] = { "bus_clk", "peripheral_clk" };
-               char *algo_group_5[] = { "cpu_clk", "peripheral_clk" };
-               char **algo_current = NULL;
-               /* 3 is the maximum number of clocks in relation */
-               struct clk *ck[3];
-               unsigned long values[3]; /* the same comment as above */
-               int part_length = -1;
-               int i;
-
-               /*
-                * all the steps below only required if adjustion was
-                * requested
-                */
-               if (algo_id == IUS_N1_N1 ||
-                   algo_id == IUS_322 ||
-                   algo_id == IUS_522 ||
-                   algo_id == IUS_N11) {
-                       algo_current = algo_group_1;
-                       part_length = 3;
-               }
-               if (algo_id == SB_N1) {
-                       algo_current = algo_group_2;
-                       part_length = 2;
-               }
-               if (algo_id == SB3_N1 ||
-                   algo_id == SB3_32 ||
-                   algo_id == SB3_43 ||
-                   algo_id == SB3_54) {
-                       algo_current = algo_group_3;
-                       part_length = 2;
-               }
-               if (algo_id == BP_N1) {
-                       algo_current = algo_group_4;
-                       part_length = 2;
-               }
-               if (algo_id == IP_N1) {
-                       algo_current = algo_group_5;
-                       part_length = 2;
-               }
-               if (!algo_current)
-                       goto incorrect_algo_id;
-
-               originator = -1;
-               for (i = 0; i < part_length; i ++ ) {
-                       if (originator >= 0 && !strcmp(clk->name,
-                                                      algo_current[i]))
-                               originator = i;
-                       ck[i] = clk_get(NULL, algo_current[i]);
-                       values[i] = clk_get_rate(ck[i]);
-               }
-
-               if (originator >= 0)
-                       adjust_clocks(originator, adjust_algos[algo_id],
-                                     values, part_length);
-
-               for (i = 0; i < part_length; i ++ ) {
-                       struct frqcr_context part_ctx;
-                       int part_div;
-
-                       if (likely(!err)) {
-                               part_div = sh7722_find_div_index(parent_rate,
-                                                               rate);
-                               if (part_div > 0) {
-                                       part_ctx = sh7722_get_clk_context(
-                                                               ck[i]->name);
-                                       frqcr &= ~(part_ctx.mask <<
-                                                  part_ctx.shift);
-                                       frqcr |= part_div << part_ctx.shift;
-                               } else
-                                       err = part_div;
-                       }
-
-                       ck[i]->ops->recalc(ck[i]);
-                       clk_put(ck[i]);
-               }
-       }
-
-       /* was there any error during recalculation ? If so, bail out.. */
-       if (unlikely(err!=0))
-               goto out_err;
-
-       /* clear FRQCR bits */
-       frqcr &= ~(ctx.mask << ctx.shift);
-       frqcr |= div << ctx.shift;
-
-       /* ...and perform actual change */
-       ctrl_outl(frqcr, FRQCR);
-       return 0;
-
-incorrect_algo_id:
-       return -EINVAL;
-out_err:
-       return err;
-}
-
-static long sh7722_frqcr_round_rate(struct clk *clk, unsigned long rate)
-{
-       unsigned long parent_rate = clk->parent->rate;
-       int div;
-
-       /* look for multiplier/divisor pair */
-       div = sh7722_find_div_index(parent_rate, rate);
-       if (div < 0)
-               return clk->rate;
-
-       /* calculate new value of clock rate */
-       return parent_rate * 2 / divisors2[div];
-}
-
-static struct clk_ops sh7722_frqcr_clk_ops = {
-       .recalc = sh7722_frqcr_recalc,
-       .set_rate = sh7722_frqcr_set_rate,
-       .round_rate = sh7722_frqcr_round_rate,
+struct clk extal_clk = {
+       .name           = "extal",
+       .id             = -1,
+       .rate           = 33333333,
 };
 
-/*
- * clock ops methods for SIU A/B and IrDA clock
- *
- */
-
-#ifndef CONFIG_CPU_SUBTYPE_SH7343
-
-static int sh7722_siu_set_rate(struct clk *clk, unsigned long rate, int algo_id)
-{
-       unsigned long r;
-       int div;
-
-       r = ctrl_inl(clk->arch_flags);
-       div = sh7722_find_div_index(clk->parent->rate, rate);
-       if (div < 0)
-               return div;
-       r = (r & ~0xF) | div;
-       ctrl_outl(r, clk->arch_flags);
-       return 0;
-}
-
-static void sh7722_siu_recalc(struct clk *clk)
-{
-       unsigned long r;
-
-       r = ctrl_inl(clk->arch_flags);
-       clk->rate = clk->parent->rate * 2 / divisors2[r & 0xF];
-}
-
-static int sh7722_siu_start_stop(struct clk *clk, int enable)
+/* The dll block multiplies the 32khz r_clk, may be used instead of extal */
+static unsigned long dll_recalc(struct clk *clk)
 {
-       unsigned long r;
+       unsigned long mult;
 
-       r = ctrl_inl(clk->arch_flags);
-       if (enable)
-               ctrl_outl(r & ~(1 << 8), clk->arch_flags);
+       if (__raw_readl(PLLCR) & 0x1000)
+               mult = __raw_readl(DLLFRQ);
        else
-               ctrl_outl(r | (1 << 8), clk->arch_flags);
-       return 0;
-}
-
-static void sh7722_siu_enable(struct clk *clk)
-{
-       sh7722_siu_start_stop(clk, 1);
-}
+               mult = 0;
 
-static void sh7722_siu_disable(struct clk *clk)
-{
-       sh7722_siu_start_stop(clk, 0);
+       return clk->parent->rate * mult;
 }
 
-static struct clk_ops sh7722_siu_clk_ops = {
-       .recalc = sh7722_siu_recalc,
-       .set_rate = sh7722_siu_set_rate,
-       .enable = sh7722_siu_enable,
-       .disable = sh7722_siu_disable,
+static struct clk_ops dll_clk_ops = {
+       .recalc         = dll_recalc,
 };
 
-#endif /* CONFIG_CPU_SUBTYPE_SH7343 */
-
-static void sh7722_video_enable(struct clk *clk)
-{
-       unsigned long r;
-
-       r = ctrl_inl(VCLKCR);
-       ctrl_outl( r & ~(1<<8), VCLKCR);
-}
-
-static void sh7722_video_disable(struct clk *clk)
-{
-       unsigned long r;
-
-       r = ctrl_inl(VCLKCR);
-       ctrl_outl( r | (1<<8), VCLKCR);
-}
+static struct clk dll_clk = {
+       .name           = "dll_clk",
+       .id             = -1,
+       .ops            = &dll_clk_ops,
+       .parent         = &r_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
 
-static int sh7722_video_set_rate(struct clk *clk, unsigned long rate,
-                                int algo_id)
+static unsigned long pll_recalc(struct clk *clk)
 {
-       unsigned long r;
-
-       r = ctrl_inl(VCLKCR);
-       r &= ~0x3F;
-       r |= ((clk->parent->rate / rate - 1) & 0x3F);
-       ctrl_outl(r, VCLKCR);
-       return 0;
-}
+       unsigned long mult = 1;
+       unsigned long div = 1;
 
-static void sh7722_video_recalc(struct clk *clk)
-{
-       unsigned long r;
+       if (__raw_readl(PLLCR) & 0x4000)
+               mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1);
+       else
+               div = 2;
 
-       r = ctrl_inl(VCLKCR);
-       clk->rate = clk->parent->rate / ((r & 0x3F) + 1);
+       return (clk->parent->rate * mult) / div;
 }
 
-static struct clk_ops sh7722_video_clk_ops = {
-       .recalc = sh7722_video_recalc,
-       .set_rate = sh7722_video_set_rate,
-       .enable = sh7722_video_enable,
-       .disable = sh7722_video_disable,
-};
-/*
- * and at last, clock definitions themselves
- */
-static struct clk sh7722_umem_clock = {
-       .name = "umem_clk",
-       .ops = &sh7722_frqcr_clk_ops,
-       .flags = CLK_RATE_PROPAGATES,
+static struct clk_ops pll_clk_ops = {
+       .recalc         = pll_recalc,
 };
 
-static struct clk sh7722_sh_clock = {
-       .name = "sh_clk",
-       .ops = &sh7722_frqcr_clk_ops,
-       .flags = CLK_RATE_PROPAGATES,
+static struct clk pll_clk = {
+       .name           = "pll_clk",
+       .id             = -1,
+       .ops            = &pll_clk_ops,
+       .flags          = CLK_ENABLE_ON_INIT,
 };
 
-static struct clk sh7722_peripheral_clock = {
-       .name = "peripheral_clk",
-       .ops = &sh7722_frqcr_clk_ops,
-       .flags = CLK_RATE_PROPAGATES,
+struct clk *main_clks[] = {
+       &r_clk,
+       &extal_clk,
+       &dll_clk,
+       &pll_clk,
 };
 
-static struct clk sh7722_sdram_clock = {
-       .name = "sdram_clk",
-       .ops = &sh7722_frqcr_clk_ops,
-};
+static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
 
-static struct clk sh7722_r_clock = {
-       .name = "r_clk",
-       .rate = 32768,
-       .flags = CLK_RATE_PROPAGATES,
+static struct clk_div_mult_table div4_table = {
+       .divisors = divisors,
+       .nr_divisors = ARRAY_SIZE(divisors),
+       .multipliers = multipliers,
+       .nr_multipliers = ARRAY_SIZE(multipliers),
 };
 
-#ifndef CONFIG_CPU_SUBTYPE_SH7343
-
-/*
- * these three clocks - SIU A, SIU B, IrDA - share the same clk_ops
- * methods of clk_ops determine which register they should access by
- * examining clk->name field
- */
-static struct clk sh7722_siu_a_clock = {
-       .name = "siu_a_clk",
-       .arch_flags = SCLKACR,
-       .ops = &sh7722_siu_clk_ops,
-};
+enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P,
+       DIV4_SIUA, DIV4_SIUB, DIV4_IRDA, DIV4_NR };
 
-static struct clk sh7722_siu_b_clock = {
-       .name = "siu_b_clk",
-       .arch_flags = SCLKBCR,
-       .ops = &sh7722_siu_clk_ops,
-};
+#define DIV4(_str, _reg, _bit, _mask, _flags) \
+  SH_CLK_DIV4(_str, &pll_clk, _reg, _bit, _mask, _flags)
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7722)
-static struct clk sh7722_irda_clock = {
-       .name = "irda_clk",
-       .arch_flags = IrDACLKCR,
-       .ops = &sh7722_siu_clk_ops,
+struct clk div4_clks[DIV4_NR] = {
+       [DIV4_I] = DIV4("cpu_clk", FRQCR, 20, 0x1fef, CLK_ENABLE_ON_INIT),
+       [DIV4_U] = DIV4("umem_clk", FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT),
+       [DIV4_SH] = DIV4("shyway_clk", FRQCR, 12, 0x1fff, CLK_ENABLE_ON_INIT),
+       [DIV4_B] = DIV4("bus_clk", FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT),
+       [DIV4_B3] = DIV4("b3_clk", FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT),
+       [DIV4_P] = DIV4("peripheral_clk", FRQCR, 0, 0x1fff, 0),
+       [DIV4_SIUA] = DIV4("siua_clk", SCLKACR, 0, 0x1fff, 0),
+       [DIV4_SIUB] = DIV4("siub_clk", SCLKBCR, 0, 0x1fff, 0),
+       [DIV4_IRDA] = DIV4("irda_clk", IRDACLKCR, 0, 0x1fff, 0),
 };
-#endif
-#endif /* CONFIG_CPU_SUBTYPE_SH7343 */
 
-static struct clk sh7722_video_clock = {
-       .name = "video_clk",
-       .ops = &sh7722_video_clk_ops,
+struct clk div6_clks[] = {
+       SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0),
 };
 
-#define MSTPCR_ARCH_FLAGS(reg, bit) (((reg) << 8) | (bit))
-#define MSTPCR_ARCH_FLAGS_REG(value) ((value) >> 8)
-#define MSTPCR_ARCH_FLAGS_BIT(value) ((value) & 0xff)
-
-static int sh7722_mstpcr_start_stop(struct clk *clk, int enable)
-{
-       unsigned long bit = MSTPCR_ARCH_FLAGS_BIT(clk->arch_flags);
-       unsigned long reg;
-       unsigned long r;
-
-       switch(MSTPCR_ARCH_FLAGS_REG(clk->arch_flags)) {
-       case 0:
-               reg = MSTPCR0;
-               break;
-       case 1:
-               reg = MSTPCR1;
-               break;
-       case 2:
-               reg = MSTPCR2;
-               break;
-       default:
-               return -EINVAL;
-       }  
-
-       r = ctrl_inl(reg);
-
-       if (enable)
-               r &= ~(1 << bit);
-       else
-               r |= (1 << bit);
+#define MSTP(_str, _parent, _reg, _bit, _flags) \
+  SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _flags)
 
-       ctrl_outl(r, reg);
-       return 0;
-}
+static struct clk mstp_clks[] = {
+       MSTP("uram0", &div4_clks[DIV4_U], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
+       MSTP("xymem0", &div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
+       MSTP("tmu0", &div4_clks[DIV4_P], MSTPCR0, 15, 0),
+       MSTP("cmt0", &r_clk, MSTPCR0, 14, 0),
+       MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0),
+       MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0),
+       MSTP("scif0", &div4_clks[DIV4_P], MSTPCR0, 7, 0),
+       MSTP("scif1", &div4_clks[DIV4_P], MSTPCR0, 6, 0),
+       MSTP("scif2", &div4_clks[DIV4_P], MSTPCR0, 5, 0),
 
-static void sh7722_mstpcr_enable(struct clk *clk)
-{
-       sh7722_mstpcr_start_stop(clk, 1);
-}
+       MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0),
+       MSTP("rtc0", &r_clk, MSTPCR1, 8, 0),
 
-static void sh7722_mstpcr_disable(struct clk *clk)
-{
-       sh7722_mstpcr_start_stop(clk, 0);
-}
-
-static void sh7722_mstpcr_recalc(struct clk *clk)
-{
-       if (clk->parent)
-               clk->rate = clk->parent->rate;
-}
-
-static struct clk_ops sh7722_mstpcr_clk_ops = {
-       .enable = sh7722_mstpcr_enable,
-       .disable = sh7722_mstpcr_disable,
-       .recalc = sh7722_mstpcr_recalc,
-};
-
-#define MSTPCR(_name, _parent, regnr, bitnr) \
-{                                              \
-       .name = _name,                          \
-       .arch_flags = MSTPCR_ARCH_FLAGS(regnr, bitnr),  \
-       .ops = (void *)_parent,         \
-}
-
-static struct clk sh7722_mstpcr_clocks[] = {
-#if defined(CONFIG_CPU_SUBTYPE_SH7722)
-       MSTPCR("uram0", "umem_clk", 0, 28),
-       MSTPCR("xymem0", "bus_clk", 0, 26),
-       MSTPCR("tmu0", "peripheral_clk", 0, 15),
-       MSTPCR("cmt0", "r_clk", 0, 14),
-       MSTPCR("rwdt0", "r_clk", 0, 13),
-       MSTPCR("flctl0", "peripheral_clk", 0, 10),
-       MSTPCR("scif0", "peripheral_clk", 0, 7),
-       MSTPCR("scif1", "peripheral_clk", 0, 6),
-       MSTPCR("scif2", "peripheral_clk", 0, 5),
-       MSTPCR("i2c0", "peripheral_clk", 1, 9),
-       MSTPCR("rtc0", "r_clk", 1, 8),
-       MSTPCR("sdhi0", "peripheral_clk", 2, 18),
-       MSTPCR("keysc0", "r_clk", 2, 14),
-       MSTPCR("usbf0", "peripheral_clk", 2, 11),
-       MSTPCR("2dg0", "bus_clk", 2, 9),
-       MSTPCR("siu0", "bus_clk", 2, 8),
-       MSTPCR("vou0", "bus_clk", 2, 5),
-       MSTPCR("jpu0", "bus_clk", 2, 6),
-       MSTPCR("beu0", "bus_clk", 2, 4),
-       MSTPCR("ceu0", "bus_clk", 2, 3),
-       MSTPCR("veu0", "bus_clk", 2, 2),
-       MSTPCR("vpu0", "bus_clk", 2, 1),
-       MSTPCR("lcdc0", "bus_clk", 2, 0),
-#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7723)
-       /* See page 60 of Datasheet V1.0: Overview -> Block Diagram */
-       MSTPCR("tlb0", "cpu_clk", 0, 31),
-       MSTPCR("ic0", "cpu_clk", 0, 30),
-       MSTPCR("oc0", "cpu_clk", 0, 29),
-       MSTPCR("l2c0", "sh_clk", 0, 28),
-       MSTPCR("ilmem0", "cpu_clk", 0, 27),
-       MSTPCR("fpu0", "cpu_clk", 0, 24),
-       MSTPCR("intc0", "cpu_clk", 0, 22),
-       MSTPCR("dmac0", "bus_clk", 0, 21),
-       MSTPCR("sh0", "sh_clk", 0, 20),
-       MSTPCR("hudi0", "peripheral_clk", 0, 19),
-       MSTPCR("ubc0", "cpu_clk", 0, 17),
-       MSTPCR("tmu0", "peripheral_clk", 0, 15),
-       MSTPCR("cmt0", "r_clk", 0, 14),
-       MSTPCR("rwdt0", "r_clk", 0, 13),
-       MSTPCR("dmac1", "bus_clk", 0, 12),
-       MSTPCR("tmu1", "peripheral_clk", 0, 11),
-       MSTPCR("flctl0", "peripheral_clk", 0, 10),
-       MSTPCR("scif0", "peripheral_clk", 0, 9),
-       MSTPCR("scif1", "peripheral_clk", 0, 8),
-       MSTPCR("scif2", "peripheral_clk", 0, 7),
-       MSTPCR("scif3", "bus_clk", 0, 6),
-       MSTPCR("scif4", "bus_clk", 0, 5),
-       MSTPCR("scif5", "bus_clk", 0, 4),
-       MSTPCR("msiof0", "bus_clk", 0, 2),
-       MSTPCR("msiof1", "bus_clk", 0, 1),
-       MSTPCR("meram0", "sh_clk", 0, 0),
-       MSTPCR("i2c0", "peripheral_clk", 1, 9),
-       MSTPCR("rtc0", "r_clk", 1, 8),
-       MSTPCR("atapi0", "sh_clk", 2, 28),
-       MSTPCR("adc0", "peripheral_clk", 2, 28),
-       MSTPCR("tpu0", "bus_clk", 2, 25),
-       MSTPCR("irda0", "peripheral_clk", 2, 24),
-       MSTPCR("tsif0", "bus_clk", 2, 22),
-       MSTPCR("icb0", "bus_clk", 2, 21),
-       MSTPCR("sdhi0", "bus_clk", 2, 18),
-       MSTPCR("sdhi1", "bus_clk", 2, 17),
-       MSTPCR("keysc0", "r_clk", 2, 14),
-       MSTPCR("usb0", "bus_clk", 2, 11),
-       MSTPCR("2dg0", "bus_clk", 2, 10),
-       MSTPCR("siu0", "bus_clk", 2, 8),
-       MSTPCR("veu1", "bus_clk", 2, 6),
-       MSTPCR("vou0", "bus_clk", 2, 5),
-       MSTPCR("beu0", "bus_clk", 2, 4),
-       MSTPCR("ceu0", "bus_clk", 2, 3),
-       MSTPCR("veu0", "bus_clk", 2, 2),
-       MSTPCR("vpu0", "bus_clk", 2, 1),
-       MSTPCR("lcdc0", "bus_clk", 2, 0),
-#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7343)
-       MSTPCR("uram0", "umem_clk", 0, 28),
-       MSTPCR("xymem0", "bus_clk", 0, 26),
-       MSTPCR("tmu0", "peripheral_clk", 0, 15),
-       MSTPCR("cmt0", "r_clk", 0, 14),
-       MSTPCR("rwdt0", "r_clk", 0, 13),
-       MSTPCR("scif0", "peripheral_clk", 0, 7),
-       MSTPCR("scif1", "peripheral_clk", 0, 6),
-       MSTPCR("scif2", "peripheral_clk", 0, 5),
-       MSTPCR("scif3", "peripheral_clk", 0, 4),
-       MSTPCR("i2c0", "peripheral_clk", 1, 9),
-       MSTPCR("i2c1", "peripheral_clk", 1, 8),
-       MSTPCR("sdhi0", "peripheral_clk", 2, 18),
-       MSTPCR("keysc0", "r_clk", 2, 14),
-       MSTPCR("usbf0", "peripheral_clk", 2, 11),
-       MSTPCR("siu0", "bus_clk", 2, 8),
-       MSTPCR("jpu0", "bus_clk", 2, 6),
-       MSTPCR("vou0", "bus_clk", 2, 5),
-       MSTPCR("beu0", "bus_clk", 2, 4),
-       MSTPCR("ceu0", "bus_clk", 2, 3),
-       MSTPCR("veu0", "bus_clk", 2, 2),
-       MSTPCR("vpu0", "bus_clk", 2, 1),
-       MSTPCR("lcdc0", "bus_clk", 2, 0),
-#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7366)
-       /* See page 52 of Datasheet V0.40: Overview -> Block Diagram */
-       MSTPCR("tlb0", "cpu_clk", 0, 31),
-       MSTPCR("ic0", "cpu_clk", 0, 30),
-       MSTPCR("oc0", "cpu_clk", 0, 29),
-       MSTPCR("rsmem0", "sh_clk", 0, 28),
-       MSTPCR("xymem0", "cpu_clk", 0, 26),
-       MSTPCR("intc30", "peripheral_clk", 0, 23),
-       MSTPCR("intc0", "peripheral_clk", 0, 22),
-       MSTPCR("dmac0", "bus_clk", 0, 21),
-       MSTPCR("sh0", "sh_clk", 0, 20),
-       MSTPCR("hudi0", "peripheral_clk", 0, 19),
-       MSTPCR("ubc0", "cpu_clk", 0, 17),
-       MSTPCR("tmu0", "peripheral_clk", 0, 15),
-       MSTPCR("cmt0", "r_clk", 0, 14),
-       MSTPCR("rwdt0", "r_clk", 0, 13),
-       MSTPCR("flctl0", "peripheral_clk", 0, 10),
-       MSTPCR("scif0", "peripheral_clk", 0, 7),
-       MSTPCR("scif1", "bus_clk", 0, 6),
-       MSTPCR("scif2", "bus_clk", 0, 5),
-       MSTPCR("msiof0", "peripheral_clk", 0, 2),
-       MSTPCR("sbr0", "peripheral_clk", 0, 1),
-       MSTPCR("i2c0", "peripheral_clk", 1, 9),
-       MSTPCR("icb0", "bus_clk", 2, 27),
-       MSTPCR("meram0", "sh_clk", 2, 26),
-       MSTPCR("dacc0", "peripheral_clk", 2, 24),
-       MSTPCR("dacy0", "peripheral_clk", 2, 23),
-       MSTPCR("tsif0", "bus_clk", 2, 22),
-       MSTPCR("sdhi0", "bus_clk", 2, 18),
-       MSTPCR("mmcif0", "bus_clk", 2, 17),
-       MSTPCR("usb0", "bus_clk", 2, 11),
-       MSTPCR("siu0", "bus_clk", 2, 8),
-       MSTPCR("veu1", "bus_clk", 2, 7),
-       MSTPCR("vou0", "bus_clk", 2, 5),
-       MSTPCR("beu0", "bus_clk", 2, 4),
-       MSTPCR("ceu0", "bus_clk", 2, 3),
-       MSTPCR("veu0", "bus_clk", 2, 2),
-       MSTPCR("vpu0", "bus_clk", 2, 1),
-       MSTPCR("lcdc0", "bus_clk", 2, 0),
-#endif
-};
-
-static struct clk *sh7722_clocks[] = {
-       &sh7722_umem_clock,
-       &sh7722_sh_clock,
-       &sh7722_peripheral_clock,
-       &sh7722_sdram_clock,
-#ifndef CONFIG_CPU_SUBTYPE_SH7343
-       &sh7722_siu_a_clock,
-       &sh7722_siu_b_clock,
-#if defined(CONFIG_CPU_SUBTYPE_SH7722)
-       &sh7722_irda_clock,
-#endif
-#endif
-       &sh7722_video_clock,
+       MSTP("sdhi0", &div4_clks[DIV4_P], MSTPCR2, 18, 0),
+       MSTP("keysc0", &r_clk, MSTPCR2, 14, 0),
+       MSTP("usbf0", &div4_clks[DIV4_P], MSTPCR2, 11, 0),
+       MSTP("2dg0", &div4_clks[DIV4_B], MSTPCR2, 9, 0),
+       MSTP("siu0", &div4_clks[DIV4_B], MSTPCR2, 8, 0),
+       MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0),
+       MSTP("jpu0", &div4_clks[DIV4_B], MSTPCR2, 6, CLK_ENABLE_ON_INIT),
+       MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0),
+       MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0),
+       MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT),
+       MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT),
+       MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0),
 };
 
-/*
- * init in order: master, module, bus, cpu
- */
-struct clk_ops *onchip_ops[] = {
-       &sh7722_master_clk_ops,
-       &sh7722_module_clk_ops,
-       &sh7722_frqcr_clk_ops,
-       &sh7722_frqcr_clk_ops,
-};
-
-void __init
-arch_init_clk_ops(struct clk_ops **ops, int type)
-{
-       BUG_ON(type < 0 || type > ARRAY_SIZE(onchip_ops));
-       *ops = onchip_ops[type];
-}
-
 int __init arch_clk_init(void)
 {
-       struct clk *clk;
-       int i;
+       int k, ret = 0;
+
+       /* autodetect extal or dll configuration */
+       if (__raw_readl(PLLCR) & 0x1000)
+               pll_clk.parent = &dll_clk;
+       else
+               pll_clk.parent = &extal_clk;
 
-       clk = clk_get(NULL, "master_clk");
-       for (i = 0; i < ARRAY_SIZE(sh7722_clocks); i++) {
-               pr_debug( "Registering clock '%s'\n", sh7722_clocks[i]->name);
-               sh7722_clocks[i]->parent = clk;
-               clk_register(sh7722_clocks[i]);
-       }
-       clk_put(clk);
+       for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+               ret = clk_register(main_clks[k]);
 
-       clk_register(&sh7722_r_clock);
+       if (!ret)
+               ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
 
-       for (i = 0; i < ARRAY_SIZE(sh7722_mstpcr_clocks); i++) {
-               pr_debug( "Registering mstpcr clock '%s'\n",
-                         sh7722_mstpcr_clocks[i].name);
-               clk = clk_get(NULL, (void *) sh7722_mstpcr_clocks[i].ops);
-               sh7722_mstpcr_clocks[i].parent = clk;
-               sh7722_mstpcr_clocks[i].ops = &sh7722_mstpcr_clk_ops;
-               clk_register(&sh7722_mstpcr_clocks[i]);
-               clk_put(clk);
-       }
+       if (!ret)
+               ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks));
 
-       clk_recalc_rate(&sh7722_r_clock); /* make sure rate gets propagated */
+       if (!ret)
+               ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks));
 
-       return 0;
+       return ret;
 }
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
new file mode 100644 (file)
index 0000000..e67c267
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7723.c
+ *
+ * SH7723 clock framework support
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * 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
+ *
+ * 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 <linux/kernel.h>
+#include <linux/io.h>
+#include <asm/clock.h>
+
+/* SH7723 registers */
+#define FRQCR          0xa4150000
+#define VCLKCR         0xa4150004
+#define SCLKACR                0xa4150008
+#define SCLKBCR                0xa415000c
+#define IRDACLKCR      0xa4150018
+#define PLLCR          0xa4150024
+#define MSTPCR0                0xa4150030
+#define MSTPCR1                0xa4150034
+#define MSTPCR2                0xa4150038
+#define DLLFRQ         0xa4150050
+
+/* Fixed 32 KHz root clock for RTC and Power Management purposes */
+static struct clk r_clk = {
+       .name           = "rclk",
+       .id             = -1,
+       .rate           = 32768,
+};
+
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+struct clk extal_clk = {
+       .name           = "extal",
+       .id             = -1,
+       .rate           = 33333333,
+};
+
+/* The dll multiplies the 32khz r_clk, may be used instead of extal */
+static unsigned long dll_recalc(struct clk *clk)
+{
+       unsigned long mult;
+
+       if (__raw_readl(PLLCR) & 0x1000)
+               mult = __raw_readl(DLLFRQ);
+       else
+               mult = 0;
+
+       return clk->parent->rate * mult;
+}
+
+static struct clk_ops dll_clk_ops = {
+       .recalc         = dll_recalc,
+};
+
+static struct clk dll_clk = {
+       .name           = "dll_clk",
+       .id             = -1,
+       .ops            = &dll_clk_ops,
+       .parent         = &r_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+static unsigned long pll_recalc(struct clk *clk)
+{
+       unsigned long mult = 1;
+       unsigned long div = 1;
+
+       if (__raw_readl(PLLCR) & 0x4000)
+               mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1);
+       else
+               div = 2;
+
+       return (clk->parent->rate * mult) / div;
+}
+
+static struct clk_ops pll_clk_ops = {
+       .recalc         = pll_recalc,
+};
+
+static struct clk pll_clk = {
+       .name           = "pll_clk",
+       .id             = -1,
+       .ops            = &pll_clk_ops,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+struct clk *main_clks[] = {
+       &r_clk,
+       &extal_clk,
+       &dll_clk,
+       &pll_clk,
+};
+
+static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
+
+static struct clk_div_mult_table div4_table = {
+       .divisors = divisors,
+       .nr_divisors = ARRAY_SIZE(divisors),
+       .multipliers = multipliers,
+       .nr_multipliers = ARRAY_SIZE(multipliers),
+};
+
+enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P,
+       DIV4_SIUA, DIV4_SIUB, DIV4_IRDA, DIV4_NR };
+
+#define DIV4(_str, _reg, _bit, _mask, _flags) \
+  SH_CLK_DIV4(_str, &pll_clk, _reg, _bit, _mask, _flags)
+
+struct clk div4_clks[DIV4_NR] = {
+       [DIV4_I] = DIV4("cpu_clk", FRQCR, 20, 0x0dbf, CLK_ENABLE_ON_INIT),
+       [DIV4_U] = DIV4("umem_clk", FRQCR, 16, 0x0dbf, CLK_ENABLE_ON_INIT),
+       [DIV4_SH] = DIV4("shyway_clk", FRQCR, 12, 0x0dbf, CLK_ENABLE_ON_INIT),
+       [DIV4_B] = DIV4("bus_clk", FRQCR, 8, 0x0dbf, CLK_ENABLE_ON_INIT),
+       [DIV4_B3] = DIV4("b3_clk", FRQCR, 4, 0x0db4, CLK_ENABLE_ON_INIT),
+       [DIV4_P] = DIV4("peripheral_clk", FRQCR, 0, 0x0dbf, 0),
+       [DIV4_SIUA] = DIV4("siua_clk", SCLKACR, 0, 0x0dbf, 0),
+       [DIV4_SIUB] = DIV4("siub_clk", SCLKBCR, 0, 0x0dbf, 0),
+       [DIV4_IRDA] = DIV4("irda_clk", IRDACLKCR, 0, 0x0dbf, 0),
+};
+
+struct clk div6_clks[] = {
+       SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0),
+};
+
+#define MSTP(_str, _parent, _reg, _bit, _force_on, _need_cpg, _need_ram) \
+  SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _force_on * CLK_ENABLE_ON_INIT)
+
+static struct clk mstp_clks[] = {
+       /* See page 60 of Datasheet V1.0: Overview -> Block Diagram */
+       MSTP("tlb0", &div4_clks[DIV4_I], MSTPCR0, 31, 1, 1, 0),
+       MSTP("ic0", &div4_clks[DIV4_I], MSTPCR0, 30, 1, 1, 0),
+       MSTP("oc0", &div4_clks[DIV4_I], MSTPCR0, 29, 1, 1, 0),
+       MSTP("l2c0", &div4_clks[DIV4_SH], MSTPCR0, 28, 1, 1, 0),
+       MSTP("ilmem0", &div4_clks[DIV4_I], MSTPCR0, 27, 1, 1, 0),
+       MSTP("fpu0", &div4_clks[DIV4_I], MSTPCR0, 24, 1, 1, 0),
+       MSTP("intc0", &div4_clks[DIV4_I], MSTPCR0, 22, 1, 1, 0),
+       MSTP("dmac0", &div4_clks[DIV4_B], MSTPCR0, 21, 0, 1, 1),
+       MSTP("sh0", &div4_clks[DIV4_SH], MSTPCR0, 20, 0, 1, 0),
+       MSTP("hudi0", &div4_clks[DIV4_P], MSTPCR0, 19, 0, 1, 0),
+       MSTP("ubc0", &div4_clks[DIV4_I], MSTPCR0, 17, 0, 1, 0),
+       MSTP("tmu0", &div4_clks[DIV4_P], MSTPCR0, 15, 0, 1, 0),
+       MSTP("cmt0", &r_clk, MSTPCR0, 14, 0, 0, 0),
+       MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0, 0, 0),
+       MSTP("dmac1", &div4_clks[DIV4_B], MSTPCR0, 12, 0, 1, 1),
+       MSTP("tmu1", &div4_clks[DIV4_P], MSTPCR0, 11, 0, 1, 0),
+       MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0, 1, 0),
+       MSTP("scif0", &div4_clks[DIV4_P], MSTPCR0, 9, 0, 1, 0),
+       MSTP("scif1", &div4_clks[DIV4_P], MSTPCR0, 8, 0, 1, 0),
+       MSTP("scif2", &div4_clks[DIV4_P], MSTPCR0, 7, 0, 1, 0),
+       MSTP("scif3", &div4_clks[DIV4_B], MSTPCR0, 6, 0, 1, 0),
+       MSTP("scif4", &div4_clks[DIV4_B], MSTPCR0, 5, 0, 1, 0),
+       MSTP("scif5", &div4_clks[DIV4_B], MSTPCR0, 4, 0, 1, 0),
+       MSTP("msiof0", &div4_clks[DIV4_B], MSTPCR0, 2, 0, 1, 0),
+       MSTP("msiof1", &div4_clks[DIV4_B], MSTPCR0, 1, 0, 1, 0),
+       MSTP("meram0", &div4_clks[DIV4_SH], MSTPCR0, 0, 1, 1, 0),
+
+       MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0, 1, 0),
+       MSTP("rtc0", &r_clk, MSTPCR1, 8, 0, 0, 0),
+
+       MSTP("atapi0", &div4_clks[DIV4_SH], MSTPCR2, 28, 0, 1, 0),
+       MSTP("adc0", &div4_clks[DIV4_P], MSTPCR2, 27, 0, 1, 0),
+       MSTP("tpu0", &div4_clks[DIV4_B], MSTPCR2, 25, 0, 1, 0),
+       MSTP("irda0", &div4_clks[DIV4_P], MSTPCR2, 24, 0, 1, 0),
+       MSTP("tsif0", &div4_clks[DIV4_B], MSTPCR2, 22, 0, 1, 0),
+       MSTP("icb0", &div4_clks[DIV4_B], MSTPCR2, 21, 0, 1, 1),
+       MSTP("sdhi0", &div4_clks[DIV4_B], MSTPCR2, 18, 0, 1, 0),
+       MSTP("sdhi1", &div4_clks[DIV4_B], MSTPCR2, 17, 0, 1, 0),
+       MSTP("keysc0", &r_clk, MSTPCR2, 14, 0, 0, 0),
+       MSTP("usb0", &div4_clks[DIV4_B], MSTPCR2, 11, 0, 1, 0),
+       MSTP("2dg0", &div4_clks[DIV4_B], MSTPCR2, 10, 0, 1, 1),
+       MSTP("siu0", &div4_clks[DIV4_B], MSTPCR2, 8, 0, 1, 0),
+       MSTP("veu1", &div4_clks[DIV4_B], MSTPCR2, 6, 1, 1, 1),
+       MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0, 1, 1),
+       MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0, 1, 1),
+       MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0, 1, 1),
+       MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, 1, 1, 1),
+       MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, 1, 1, 1),
+       MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0, 1, 1),
+};
+
+int __init arch_clk_init(void)
+{
+       int k, ret = 0;
+
+       /* autodetect extal or dll configuration */
+       if (__raw_readl(PLLCR) & 0x1000)
+               pll_clk.parent = &dll_clk;
+       else
+               pll_clk.parent = &extal_clk;
+
+       for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+               ret = clk_register(main_clks[k]);
+
+       if (!ret)
+               ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+       if (!ret)
+               ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks));
+
+       if (!ret)
+               ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks));
+
+       return ret;
+}
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
new file mode 100644 (file)
index 0000000..5d5c9b9
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7724.c
+ *
+ * SH7724 clock framework support
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * 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
+ *
+ * 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 <linux/kernel.h>
+#include <linux/io.h>
+#include <asm/clock.h>
+
+/* SH7724 registers */
+#define FRQCRA         0xa4150000
+#define FRQCRB         0xa4150004
+#define VCLKCR         0xa4150048
+#define FCLKACR                0xa4150008
+#define FCLKBCR                0xa415000c
+#define IRDACLKCR      0xa4150018
+#define PLLCR          0xa4150024
+#define MSTPCR0                0xa4150030
+#define MSTPCR1                0xa4150034
+#define MSTPCR2                0xa4150038
+#define SPUCLKCR       0xa415003c
+#define FLLFRQ         0xa4150050
+#define LSTATS         0xa4150060
+
+/* Fixed 32 KHz root clock for RTC and Power Management purposes */
+static struct clk r_clk = {
+       .name           = "rclk",
+       .id             = -1,
+       .rate           = 32768,
+};
+
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+struct clk extal_clk = {
+       .name           = "extal",
+       .id             = -1,
+       .rate           = 33333333,
+};
+
+/* The fll multiplies the 32khz r_clk, may be used instead of extal */
+static unsigned long fll_recalc(struct clk *clk)
+{
+       unsigned long mult = 0;
+       unsigned long div = 1;
+
+       if (__raw_readl(PLLCR) & 0x1000)
+               mult = __raw_readl(FLLFRQ) & 0x3ff;
+
+       if (__raw_readl(FLLFRQ) & 0x4000)
+               div = 2;
+
+       return (clk->parent->rate * mult) / div;
+}
+
+static struct clk_ops fll_clk_ops = {
+       .recalc         = fll_recalc,
+};
+
+static struct clk fll_clk = {
+       .name           = "fll_clk",
+       .id             = -1,
+       .ops            = &fll_clk_ops,
+       .parent         = &r_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+static unsigned long pll_recalc(struct clk *clk)
+{
+       unsigned long mult = 1;
+
+       if (__raw_readl(PLLCR) & 0x4000)
+               mult = (((__raw_readl(FRQCRA) >> 24) & 0x3f) + 1) * 2;
+
+       return clk->parent->rate * mult;
+}
+
+static struct clk_ops pll_clk_ops = {
+       .recalc         = pll_recalc,
+};
+
+static struct clk pll_clk = {
+       .name           = "pll_clk",
+       .id             = -1,
+       .ops            = &pll_clk_ops,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+/* A fixed divide-by-3 block use by the div6 clocks */
+static unsigned long div3_recalc(struct clk *clk)
+{
+       return clk->parent->rate / 3;
+}
+
+static struct clk_ops div3_clk_ops = {
+       .recalc         = div3_recalc,
+};
+
+static struct clk div3_clk = {
+       .name           = "div3_clk",
+       .id             = -1,
+       .ops            = &div3_clk_ops,
+       .parent         = &pll_clk,
+};
+
+struct clk *main_clks[] = {
+       &r_clk,
+       &extal_clk,
+       &fll_clk,
+       &pll_clk,
+       &div3_clk,
+};
+
+static int divisors[] = { 2, 0, 4, 6, 8, 12, 16, 0, 24, 32, 36, 48, 0, 72 };
+
+static struct clk_div_mult_table div4_table = {
+       .divisors = divisors,
+       .nr_divisors = ARRAY_SIZE(divisors),
+};
+
+enum { DIV4_I, DIV4_SH, DIV4_B, DIV4_P, DIV4_M1, DIV4_NR };
+
+#define DIV4(_str, _reg, _bit, _mask, _flags) \
+  SH_CLK_DIV4(_str, &pll_clk, _reg, _bit, _mask, _flags)
+
+struct clk div4_clks[DIV4_NR] = {
+       [DIV4_I] = DIV4("cpu_clk", FRQCRA, 20, 0x2f7d, CLK_ENABLE_ON_INIT),
+       [DIV4_SH] = DIV4("shyway_clk", FRQCRA, 12, 0x2f7c, CLK_ENABLE_ON_INIT),
+       [DIV4_B] = DIV4("bus_clk", FRQCRA, 8, 0x2f7c, CLK_ENABLE_ON_INIT),
+       [DIV4_P] = DIV4("peripheral_clk", FRQCRA, 0, 0x2f7c, 0),
+       [DIV4_M1] = DIV4("vpu_clk", FRQCRB, 4, 0x2f7c, 0),
+};
+
+struct clk div6_clks[] = {
+       SH_CLK_DIV6("video_clk", &div3_clk, VCLKCR, 0),
+       SH_CLK_DIV6("fsia_clk", &div3_clk, FCLKACR, 0),
+       SH_CLK_DIV6("fsib_clk", &div3_clk, FCLKBCR, 0),
+       SH_CLK_DIV6("irda_clk", &div3_clk, IRDACLKCR, 0),
+       SH_CLK_DIV6("spu_clk", &div3_clk, SPUCLKCR, 0),
+};
+
+#define MSTP(_str, _parent, _reg, _bit, _force_on, _need_cpg, _need_ram) \
+  SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _force_on * CLK_ENABLE_ON_INIT)
+
+static struct clk mstp_clks[] = {
+       MSTP("tlb0", &div4_clks[DIV4_I], MSTPCR0, 31, 1, 1, 0),
+       MSTP("ic0", &div4_clks[DIV4_I], MSTPCR0, 30, 1, 1, 0),
+       MSTP("oc0", &div4_clks[DIV4_I], MSTPCR0, 29, 1, 1, 0),
+       MSTP("rs0", &div4_clks[DIV4_B], MSTPCR0, 28, 1, 1, 0),
+       MSTP("ilmem0", &div4_clks[DIV4_I], MSTPCR0, 27, 1, 1, 0),
+       MSTP("l2c0", &div4_clks[DIV4_SH], MSTPCR0, 26, 1, 1, 0),
+       MSTP("fpu0", &div4_clks[DIV4_I], MSTPCR0, 24, 1, 1, 0),
+       MSTP("intc0", &div4_clks[DIV4_P], MSTPCR0, 22, 1, 1, 0),
+       MSTP("dmac0", &div4_clks[DIV4_B], MSTPCR0, 21, 0, 1, 1),
+       MSTP("sh0", &div4_clks[DIV4_SH], MSTPCR0, 20, 0, 1, 0),
+       MSTP("hudi0", &div4_clks[DIV4_P], MSTPCR0, 19, 0, 1, 0),
+       MSTP("ubc0", &div4_clks[DIV4_I], MSTPCR0, 17, 0, 1, 0),
+       MSTP("tmu0", &div4_clks[DIV4_P], MSTPCR0, 15, 0, 1, 0),
+       MSTP("cmt0", &r_clk, MSTPCR0, 14, 0, 0, 0),
+       MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0, 0, 0),
+       MSTP("dmac1", &div4_clks[DIV4_B], MSTPCR0, 12, 0, 1, 1),
+       MSTP("tmu1", &div4_clks[DIV4_P], MSTPCR0, 10, 0, 1, 0),
+       MSTP("scif0", &div4_clks[DIV4_P], MSTPCR0, 9, 0, 1, 0),
+       MSTP("scif1", &div4_clks[DIV4_P], MSTPCR0, 8, 0, 1, 0),
+       MSTP("scif2", &div4_clks[DIV4_P], MSTPCR0, 7, 0, 1, 0),
+       MSTP("scif3", &div4_clks[DIV4_B], MSTPCR0, 6, 0, 1, 0),
+       MSTP("scif4", &div4_clks[DIV4_B], MSTPCR0, 5, 0, 1, 0),
+       MSTP("scif5", &div4_clks[DIV4_B], MSTPCR0, 4, 0, 1, 0),
+       MSTP("msiof0", &div4_clks[DIV4_B], MSTPCR0, 2, 0, 1, 0),
+       MSTP("msiof1", &div4_clks[DIV4_B], MSTPCR0, 1, 0, 1, 0),
+
+       MSTP("keysc0", &r_clk, MSTPCR1, 12, 0, 0, 0),
+       MSTP("rtc0", &r_clk, MSTPCR1, 11, 0, 0, 0),
+       MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0, 1, 0),
+       MSTP("i2c1", &div4_clks[DIV4_P], MSTPCR1, 8, 0, 1, 0),
+
+       MSTP("mmc0", &div4_clks[DIV4_B], MSTPCR2, 29, 0, 1, 0),
+       MSTP("eth0", &div4_clks[DIV4_B], MSTPCR2, 28, 0, 1, 0),
+       MSTP("atapi0", &div4_clks[DIV4_B], MSTPCR2, 26, 0, 1, 0),
+       MSTP("tpu0", &div4_clks[DIV4_B], MSTPCR2, 25, 0, 1, 0),
+       MSTP("irda0", &div4_clks[DIV4_P], MSTPCR2, 24, 0, 1, 0),
+       MSTP("tsif0", &div4_clks[DIV4_B], MSTPCR2, 22, 0, 1, 0),
+       MSTP("usb1", &div4_clks[DIV4_B], MSTPCR2, 21, 0, 1, 1),
+       MSTP("usb0", &div4_clks[DIV4_B], MSTPCR2, 20, 0, 1, 1),
+       MSTP("2dg0", &div4_clks[DIV4_B], MSTPCR2, 19, 0, 1, 1),
+       MSTP("sdhi0", &div4_clks[DIV4_B], MSTPCR2, 18, 0, 1, 0),
+       MSTP("sdhi1", &div4_clks[DIV4_B], MSTPCR2, 17, 0, 1, 0),
+       MSTP("veu1", &div4_clks[DIV4_B], MSTPCR2, 15, 1, 1, 1),
+       MSTP("ceu1", &div4_clks[DIV4_B], MSTPCR2, 13, 0, 1, 1),
+       MSTP("beu1", &div4_clks[DIV4_B], MSTPCR2, 12, 0, 1, 1),
+       MSTP("2ddmac0", &div4_clks[DIV4_SH], MSTPCR2, 10, 0, 1, 1),
+       MSTP("spu0", &div4_clks[DIV4_B], MSTPCR2, 9, 0, 1, 0),
+       MSTP("jpu0", &div4_clks[DIV4_B], MSTPCR2, 6, 1, 1, 1),
+       MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0, 1, 1),
+       MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0, 1, 1),
+       MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0, 1, 1),
+       MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, 1, 1, 1),
+       MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, 1, 1, 1),
+       MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0, 1, 1),
+};
+
+int __init arch_clk_init(void)
+{
+       int k, ret = 0;
+
+       /* autodetect extal or fll configuration */
+       if (__raw_readl(PLLCR) & 0x1000)
+               pll_clk.parent = &fll_clk;
+       else
+               pll_clk.parent = &extal_clk;
+
+       for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+               ret = clk_register(main_clks[k]);
+
+       if (!ret)
+               ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+       if (!ret)
+               ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks));
+
+       if (!ret)
+               ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks));
+
+       return ret;
+}
index 3177d0d1e06da240cac4fccf5e56a90c7c2b19f9..370cd47642efcbfc3ec36827a3a581ba4bf7bc7a 100644 (file)
@@ -29,33 +29,28 @@ static struct clk_ops sh7763_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQCR) >> 4) & 0x07);
-       clk->rate = clk->parent->rate / p0fc_divisors[idx];
+       return clk->parent->rate / p0fc_divisors[idx];
 }
 
 static struct clk_ops sh7763_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQCR) >> 16) & 0x07);
-       clk->rate = clk->parent->rate / bfc_divisors[idx];
+       return clk->parent->rate / bfc_divisors[idx];
 }
 
 static struct clk_ops sh7763_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
-{
-       clk->rate = clk->parent->rate;
-}
-
 static struct clk_ops sh7763_cpu_clk_ops = {
-       .recalc         = cpu_clk_recalc,
+       .recalc         = followparent_recalc,
 };
 
 static struct clk_ops *sh7763_clk_ops[] = {
@@ -71,10 +66,10 @@ void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
                *ops = sh7763_clk_ops[idx];
 }
 
-static void shyway_clk_recalc(struct clk *clk)
+static unsigned long shyway_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQCR) >> 20) & 0x07);
-       clk->rate = clk->parent->rate / cfc_divisors[idx];
+       return clk->parent->rate / cfc_divisors[idx];
 }
 
 static struct clk_ops sh7763_shyway_clk_ops = {
@@ -83,7 +78,7 @@ static struct clk_ops sh7763_shyway_clk_ops = {
 
 static struct clk sh7763_shyway_clk = {
        .name           = "shyway_clk",
-       .flags          = CLK_ALWAYS_ENABLED,
+       .flags          = CLK_ENABLE_ON_INIT,
        .ops            = &sh7763_shyway_clk_ops,
 };
 
@@ -95,31 +90,22 @@ static struct clk *sh7763_onchip_clocks[] = {
        &sh7763_shyway_clk,
 };
 
-static int __init sh7763_clk_init(void)
+int __init arch_clk_init(void)
 {
-       struct clk *clk = clk_get(NULL, "master_clk");
-       int i;
+       struct clk *clk;
+       int i, ret = 0;
+
+       cpg_clk_init();
 
+       clk = clk_get(NULL, "master_clk");
        for (i = 0; i < ARRAY_SIZE(sh7763_onchip_clocks); i++) {
                struct clk *clkp = sh7763_onchip_clocks[i];
 
                clkp->parent = clk;
-               clk_register(clkp);
-               clk_enable(clkp);
+               ret |= clk_register(clkp);
        }
 
-       /*
-        * Now that we have the rest of the clocks registered, we need to
-        * force the parent clock to propagate so that these clocks will
-        * automatically figure out their rate. We cheat by handing the
-        * parent clock its current rate and forcing child propagation.
-        */
-       clk_set_rate(clk, clk_get_rate(clk));
-
        clk_put(clk);
 
-       return 0;
+       return ret;
 }
-
-arch_initcall(sh7763_clk_init);
-
index 8e236062c721860fb5f39768c09f4eb2859bb6cc..e0b896769205a291809ac035dab984c309db3392 100644 (file)
@@ -28,30 +28,30 @@ static struct clk_ops sh7770_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQCR) >> 28) & 0x000f);
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
+       return clk->parent->rate / pfc_divisors[idx];
 }
 
 static struct clk_ops sh7770_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inl(FRQCR) & 0x000f);
-       clk->rate = clk->parent->rate / bfc_divisors[idx];
+       return clk->parent->rate / bfc_divisors[idx];
 }
 
 static struct clk_ops sh7770_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
+static unsigned long cpu_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQCR) >> 24) & 0x000f);
-       clk->rate = clk->parent->rate / ifc_divisors[idx];
+       return clk->parent->rate / ifc_divisors[idx];
 }
 
 static struct clk_ops sh7770_cpu_clk_ops = {
index 01f3da619d3d95f259b19153e556fe1ea721718f..a249d823578ea1406468bfa75d4c84c9c0f0b24e 100644 (file)
@@ -29,30 +29,30 @@ static struct clk_ops sh7780_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inl(FRQCR) & 0x0003);
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
+       return clk->parent->rate / pfc_divisors[idx];
 }
 
 static struct clk_ops sh7780_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQCR) >> 16) & 0x0007);
-       clk->rate = clk->parent->rate / bfc_divisors[idx];
+       return clk->parent->rate / bfc_divisors[idx];
 }
 
 static struct clk_ops sh7780_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
+static unsigned long cpu_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQCR) >> 24) & 0x0001);
-       clk->rate = clk->parent->rate / ifc_divisors[idx];
+       return clk->parent->rate / ifc_divisors[idx];
 }
 
 static struct clk_ops sh7780_cpu_clk_ops = {
@@ -72,10 +72,10 @@ void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
                *ops = sh7780_clk_ops[idx];
 }
 
-static void shyway_clk_recalc(struct clk *clk)
+static unsigned long shyway_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQCR) >> 20) & 0x0007);
-       clk->rate = clk->parent->rate / cfc_divisors[idx];
+       return clk->parent->rate / cfc_divisors[idx];
 }
 
 static struct clk_ops sh7780_shyway_clk_ops = {
@@ -84,7 +84,7 @@ static struct clk_ops sh7780_shyway_clk_ops = {
 
 static struct clk sh7780_shyway_clk = {
        .name           = "shyway_clk",
-       .flags          = CLK_ALWAYS_ENABLED,
+       .flags          = CLK_ENABLE_ON_INIT,
        .ops            = &sh7780_shyway_clk_ops,
 };
 
@@ -96,31 +96,22 @@ static struct clk *sh7780_onchip_clocks[] = {
        &sh7780_shyway_clk,
 };
 
-static int __init sh7780_clk_init(void)
+int __init arch_clk_init(void)
 {
-       struct clk *clk = clk_get(NULL, "master_clk");
-       int i;
+       struct clk *clk;
+       int i, ret = 0;
 
+       cpg_clk_init();
+
+       clk = clk_get(NULL, "master_clk");
        for (i = 0; i < ARRAY_SIZE(sh7780_onchip_clocks); i++) {
                struct clk *clkp = sh7780_onchip_clocks[i];
 
                clkp->parent = clk;
-               clk_register(clkp);
-               clk_enable(clkp);
+               ret |= clk_register(clkp);
        }
 
-       /*
-        * Now that we have the rest of the clocks registered, we need to
-        * force the parent clock to propagate so that these clocks will
-        * automatically figure out their rate. We cheat by handing the
-        * parent clock its current rate and forcing child propagation.
-        */
-       clk_set_rate(clk, clk_get_rate(clk));
-
        clk_put(clk);
 
-       return 0;
+       return ret;
 }
-
-arch_initcall(sh7780_clk_init);
-
index 27fa81bef6a07f4a4b1cfceb525dba54ed706fb1..73abfbf2f16d29aa79e9255278725210e365b981 100644 (file)
@@ -3,7 +3,7 @@
  *
  * SH7785 support for the clock framework
  *
- *  Copyright (C) 2007  Paul Mundt
+ *  Copyright (C) 2007 - 2009  Paul Mundt
  *
  * 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
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/cpufreq.h>
 #include <asm/clock.h>
 #include <asm/freq.h>
-#include <asm/io.h>
-
-static int ifc_divisors[] = { 1, 2, 4, 6 };
-static int ufc_divisors[] = { 1, 1, 4, 6 };
-static int sfc_divisors[] = { 1, 1, 4, 6 };
-static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18,
-                            24, 32, 36, 48, 1, 1, 1, 1 };
-static int mfc_divisors[] = { 1, 1, 4, 6 };
-static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18,
-                             24, 32, 36, 48, 1, 1, 1, 1 };
-
-static void master_clk_init(struct clk *clk)
-{
-       clk->rate *= pfc_divisors[ctrl_inl(FRQMR1) & 0x000f];
-}
+#include <cpu/sh7785.h>
 
-static struct clk_ops sh7785_master_clk_ops = {
-       .init           = master_clk_init,
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+       .name           = "extal",
+       .id             = -1,
+       .rate           = 33333333,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long pll_recalc(struct clk *clk)
 {
-       int idx = (ctrl_inl(FRQMR1) & 0x000f);
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
-}
+       int multiplier;
 
-static struct clk_ops sh7785_module_clk_ops = {
-       .recalc         = module_clk_recalc,
-};
+       multiplier = test_mode_pin(MODE_PIN4) ? 36 : 72;
 
-static void bus_clk_recalc(struct clk *clk)
-{
-       int idx = ((ctrl_inl(FRQMR1) >> 16) & 0x000f);
-       clk->rate = clk->parent->rate / bfc_divisors[idx];
+       return clk->parent->rate * multiplier;
 }
 
-static struct clk_ops sh7785_bus_clk_ops = {
-       .recalc         = bus_clk_recalc,
+static struct clk_ops pll_clk_ops = {
+       .recalc         = pll_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
-{
-       int idx = ((ctrl_inl(FRQMR1) >> 28) & 0x0003);
-       clk->rate = clk->parent->rate / ifc_divisors[idx];
-}
-
-static struct clk_ops sh7785_cpu_clk_ops = {
-       .recalc         = cpu_clk_recalc,
+static struct clk pll_clk = {
+       .name           = "pll_clk",
+       .id             = -1,
+       .ops            = &pll_clk_ops,
+       .parent         = &extal_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
 };
 
-static struct clk_ops *sh7785_clk_ops[] = {
-       &sh7785_master_clk_ops,
-       &sh7785_module_clk_ops,
-       &sh7785_bus_clk_ops,
-       &sh7785_cpu_clk_ops,
+static struct clk *clks[] = {
+       &extal_clk,
+       &pll_clk,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
-{
-       if (idx < ARRAY_SIZE(sh7785_clk_ops))
-               *ops = sh7785_clk_ops[idx];
-}
-
-static void shyway_clk_recalc(struct clk *clk)
-{
-       int idx = ((ctrl_inl(FRQMR1) >> 20) & 0x0003);
-       clk->rate = clk->parent->rate / sfc_divisors[idx];
-}
+static unsigned int div2[] = { 1, 2, 4, 6, 8, 12, 16, 18,
+                              24, 32, 36, 48 };
 
-static struct clk_ops sh7785_shyway_clk_ops = {
-       .recalc         = shyway_clk_recalc,
+static struct clk_div_mult_table div4_table = {
+       .divisors = div2,
+       .nr_divisors = ARRAY_SIZE(div2),
 };
 
-static struct clk sh7785_shyway_clk = {
-       .name           = "shyway_clk",
-       .flags          = CLK_ALWAYS_ENABLED,
-       .ops            = &sh7785_shyway_clk_ops,
+enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_DDR, DIV4_GA,
+       DIV4_DU, DIV4_P, DIV4_NR };
+
+#define DIV4(_str, _bit, _mask, _flags) \
+  SH_CLK_DIV4(_str, &pll_clk, FRQMR1, _bit, _mask, _flags)
+
+struct clk div4_clks[DIV4_NR] = {
+       [DIV4_P] = DIV4("peripheral_clk", 0, 0x0f80, 0),
+       [DIV4_DU] = DIV4("du_clk", 4, 0x0ff0, 0),
+       [DIV4_GA] = DIV4("ga_clk", 8, 0x0030, 0),
+       [DIV4_DDR] = DIV4("ddr_clk", 12, 0x000c, CLK_ENABLE_ON_INIT),
+       [DIV4_B] = DIV4("bus_clk", 16, 0x0fe0, CLK_ENABLE_ON_INIT),
+       [DIV4_SH] = DIV4("shyway_clk", 20, 0x000c, CLK_ENABLE_ON_INIT),
+       [DIV4_U] = DIV4("umem_clk", 24, 0x000c, CLK_ENABLE_ON_INIT),
+       [DIV4_I] = DIV4("cpu_clk", 28, 0x000e, CLK_ENABLE_ON_INIT),
 };
 
-static void ddr_clk_recalc(struct clk *clk)
-{
-       int idx = ((ctrl_inl(FRQMR1) >> 12) & 0x0003);
-       clk->rate = clk->parent->rate / mfc_divisors[idx];
-}
-
-static struct clk_ops sh7785_ddr_clk_ops = {
-       .recalc         = ddr_clk_recalc,
-};
-
-static struct clk sh7785_ddr_clk = {
-       .name           = "ddr_clk",
-       .flags          = CLK_ALWAYS_ENABLED,
-       .ops            = &sh7785_ddr_clk_ops,
-};
-
-static void ram_clk_recalc(struct clk *clk)
-{
-       int idx = ((ctrl_inl(FRQMR1) >> 24) & 0x0003);
-       clk->rate = clk->parent->rate / ufc_divisors[idx];
-}
-
-static struct clk_ops sh7785_ram_clk_ops = {
-       .recalc         = ram_clk_recalc,
+#define MSTPCR0                0xffc80030
+#define MSTPCR1                0xffc80034
+
+static struct clk mstp_clks[] = {
+       /* MSTPCR0 */
+       SH_CLK_MSTP32("scif_fck", 5, &div4_clks[DIV4_P], MSTPCR0, 29, 0),
+       SH_CLK_MSTP32("scif_fck", 4, &div4_clks[DIV4_P], MSTPCR0, 28, 0),
+       SH_CLK_MSTP32("scif_fck", 3, &div4_clks[DIV4_P], MSTPCR0, 27, 0),
+       SH_CLK_MSTP32("scif_fck", 2, &div4_clks[DIV4_P], MSTPCR0, 26, 0),
+       SH_CLK_MSTP32("scif_fck", 1, &div4_clks[DIV4_P], MSTPCR0, 25, 0),
+       SH_CLK_MSTP32("scif_fck", 0, &div4_clks[DIV4_P], MSTPCR0, 24, 0),
+       SH_CLK_MSTP32("ssi_fck", 1, &div4_clks[DIV4_P], MSTPCR0, 21, 0),
+       SH_CLK_MSTP32("ssi_fck", 0, &div4_clks[DIV4_P], MSTPCR0, 20, 0),
+       SH_CLK_MSTP32("hac_fck", 1, &div4_clks[DIV4_P], MSTPCR0, 17, 0),
+       SH_CLK_MSTP32("hac_fck", 0, &div4_clks[DIV4_P], MSTPCR0, 16, 0),
+       SH_CLK_MSTP32("mmcif_fck", -1, &div4_clks[DIV4_P], MSTPCR0, 13, 0),
+       SH_CLK_MSTP32("flctl_fck", -1, &div4_clks[DIV4_P], MSTPCR0, 12, 0),
+       SH_CLK_MSTP32("tmu345_fck", -1, &div4_clks[DIV4_P], MSTPCR0, 9, 0),
+       SH_CLK_MSTP32("tmu012_fck", -1, &div4_clks[DIV4_P], MSTPCR0, 8, 0),
+       SH_CLK_MSTP32("siof_fck", -1, &div4_clks[DIV4_P], MSTPCR0, 3, 0),
+       SH_CLK_MSTP32("hspi_fck", -1, &div4_clks[DIV4_P], MSTPCR0, 2, 0),
+
+       /* MSTPCR1 */
+       SH_CLK_MSTP32("hudi_fck", -1, NULL, MSTPCR1, 19, 0),
+       SH_CLK_MSTP32("ubc_fck", -1, NULL, MSTPCR1, 17, 0),
+       SH_CLK_MSTP32("dmac_11_6_fck", -1, NULL, MSTPCR1, 5, 0),
+       SH_CLK_MSTP32("dmac_5_0_fck", -1, NULL, MSTPCR1, 4, 0),
+       SH_CLK_MSTP32("gdta_fck", -1, NULL, MSTPCR1, 0, 0),
 };
 
-static struct clk sh7785_ram_clk = {
-       .name           = "ram_clk",
-       .flags          = CLK_ALWAYS_ENABLED,
-       .ops            = &sh7785_ram_clk_ops,
-};
-
-/*
- * Additional SH7785-specific on-chip clocks that aren't already part of the
- * clock framework
- */
-static struct clk *sh7785_onchip_clocks[] = {
-       &sh7785_shyway_clk,
-       &sh7785_ddr_clk,
-       &sh7785_ram_clk,
-};
-
-static int __init sh7785_clk_init(void)
+int __init arch_clk_init(void)
 {
-       struct clk *clk = clk_get(NULL, "master_clk");
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(sh7785_onchip_clocks); i++) {
-               struct clk *clkp = sh7785_onchip_clocks[i];
-
-               clkp->parent = clk;
-               clk_register(clkp);
-               clk_enable(clkp);
-       }
+       int i, ret = 0;
 
-       /*
-        * Now that we have the rest of the clocks registered, we need to
-        * force the parent clock to propagate so that these clocks will
-        * automatically figure out their rate. We cheat by handing the
-        * parent clock its current rate and forcing child propagation.
-        */
-       clk_set_rate(clk, clk_get_rate(clk));
+       for (i = 0; i < ARRAY_SIZE(clks); i++)
+               ret |= clk_register(clks[i]);
 
-       clk_put(clk);
+       if (!ret)
+               ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+                                          &div4_table);
+       if (!ret)
+               ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks));
 
-       return 0;
+       return ret;
 }
-arch_initcall(sh7785_clk_init);
index f84a9c1344710ea3777c47275eeec8b47f73a30e..a0e8869071ace5480fa1d9f3857b5c8f9af102c5 100644 (file)
@@ -36,30 +36,30 @@ static struct clk_ops sh7786_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inl(FRQMR1) & 0x000f);
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
+       return clk->parent->rate / pfc_divisors[idx];
 }
 
 static struct clk_ops sh7786_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQMR1) >> 16) & 0x000f);
-       clk->rate = clk->parent->rate / bfc_divisors[idx];
+       return clk->parent->rate / bfc_divisors[idx];
 }
 
 static struct clk_ops sh7786_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
+static unsigned long cpu_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQMR1) >> 28) & 0x0003);
-       clk->rate = clk->parent->rate / ifc_divisors[idx];
+       return clk->parent->rate / ifc_divisors[idx];
 }
 
 static struct clk_ops sh7786_cpu_clk_ops = {
@@ -79,10 +79,10 @@ void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
                *ops = sh7786_clk_ops[idx];
 }
 
-static void shyway_clk_recalc(struct clk *clk)
+static unsigned long shyway_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQMR1) >> 20) & 0x0003);
-       clk->rate = clk->parent->rate / sfc_divisors[idx];
+       return clk->parent->rate / sfc_divisors[idx];
 }
 
 static struct clk_ops sh7786_shyway_clk_ops = {
@@ -91,14 +91,14 @@ static struct clk_ops sh7786_shyway_clk_ops = {
 
 static struct clk sh7786_shyway_clk = {
        .name           = "shyway_clk",
-       .flags          = CLK_ALWAYS_ENABLED,
+       .flags          = CLK_ENABLE_ON_INIT,
        .ops            = &sh7786_shyway_clk_ops,
 };
 
-static void ddr_clk_recalc(struct clk *clk)
+static unsigned long ddr_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQMR1) >> 12) & 0x0003);
-       clk->rate = clk->parent->rate / mfc_divisors[idx];
+       return clk->parent->rate / mfc_divisors[idx];
 }
 
 static struct clk_ops sh7786_ddr_clk_ops = {
@@ -107,7 +107,7 @@ static struct clk_ops sh7786_ddr_clk_ops = {
 
 static struct clk sh7786_ddr_clk = {
        .name           = "ddr_clk",
-       .flags          = CLK_ALWAYS_ENABLED,
+       .flags          = CLK_ENABLE_ON_INIT,
        .ops            = &sh7786_ddr_clk_ops,
 };
 
@@ -120,29 +120,22 @@ static struct clk *sh7786_onchip_clocks[] = {
        &sh7786_ddr_clk,
 };
 
-static int __init sh7786_clk_init(void)
+int __init arch_clk_init(void)
 {
-       struct clk *clk = clk_get(NULL, "master_clk");
-       int i;
+       struct clk *clk;
+       int i, ret = 0;
 
+       cpg_clk_init();
+
+       clk = clk_get(NULL, "master_clk");
        for (i = 0; i < ARRAY_SIZE(sh7786_onchip_clocks); i++) {
                struct clk *clkp = sh7786_onchip_clocks[i];
 
                clkp->parent = clk;
-               clk_register(clkp);
-               clk_enable(clkp);
+               ret |= clk_register(clkp);
        }
 
-       /*
-        * Now that we have the rest of the clocks registered, we need to
-        * force the parent clock to propagate so that these clocks will
-        * automatically figure out their rate. We cheat by handing the
-        * parent clock its current rate and forcing child propagation.
-        */
-       clk_set_rate(clk, clk_get_rate(clk));
-
        clk_put(clk);
 
-       return 0;
+       return ret;
 }
-arch_initcall(sh7786_clk_init);
index c630b29e06a81def79e3d4dee82dd1e7e9a1cb72..23c27d32d9823136e38f725dca53f6ffe92b76b5 100644 (file)
@@ -40,30 +40,30 @@ static struct clk_ops shx3_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQCR) >> PFC_POS) & PFC_MSK);
-       clk->rate = clk->parent->rate / pfc_divisors[idx];
+       return clk->parent->rate / pfc_divisors[idx];
 }
 
 static struct clk_ops shx3_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQCR) >> BFC_POS) & BFC_MSK);
-       clk->rate = clk->parent->rate / bfc_divisors[idx];
+       return clk->parent->rate / bfc_divisors[idx];
 }
 
 static struct clk_ops shx3_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
+static unsigned long cpu_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQCR) >> IFC_POS) & IFC_MSK);
-       clk->rate = clk->parent->rate / ifc_divisors[idx];
+       return clk->parent->rate / ifc_divisors[idx];
 }
 
 static struct clk_ops shx3_cpu_clk_ops = {
@@ -83,10 +83,10 @@ void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
                *ops = shx3_clk_ops[idx];
 }
 
-static void shyway_clk_recalc(struct clk *clk)
+static unsigned long shyway_clk_recalc(struct clk *clk)
 {
        int idx = ((ctrl_inl(FRQCR) >> CFC_POS) & CFC_MSK);
-       clk->rate = clk->parent->rate / cfc_divisors[idx];
+       return clk->parent->rate / cfc_divisors[idx];
 }
 
 static struct clk_ops shx3_shyway_clk_ops = {
@@ -95,7 +95,7 @@ static struct clk_ops shx3_shyway_clk_ops = {
 
 static struct clk shx3_shyway_clk = {
        .name           = "shyway_clk",
-       .flags          = CLK_ALWAYS_ENABLED,
+       .flags          = CLK_ENABLE_ON_INIT,
        .ops            = &shx3_shyway_clk_ops,
 };
 
@@ -107,29 +107,22 @@ static struct clk *shx3_onchip_clocks[] = {
        &shx3_shyway_clk,
 };
 
-static int __init shx3_clk_init(void)
+int __init arch_clk_init(void)
 {
-       struct clk *clk = clk_get(NULL, "master_clk");
-       int i;
+       struct clk *clk;
+       int i, ret = 0;
 
+       cpg_clk_init();
+
+       clk = clk_get(NULL, "master_clk");
        for (i = 0; i < ARRAY_SIZE(shx3_onchip_clocks); i++) {
                struct clk *clkp = shx3_onchip_clocks[i];
 
                clkp->parent = clk;
-               clk_register(clkp);
-               clk_enable(clkp);
+               ret |= clk_register(clkp);
        }
 
-       /*
-        * Now that we have the rest of the clocks registered, we need to
-        * force the parent clock to propagate so that these clocks will
-        * automatically figure out their rate. We cheat by handing the
-        * parent clock its current rate and forcing child propagation.
-        */
-       clk_set_rate(clk, clk_get_rate(clk));
-
        clk_put(clk);
 
-       return 0;
+       return ret;
 }
-arch_initcall(shx3_clk_init);
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7724.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7724.c
new file mode 100644 (file)
index 0000000..1af0f95
--- /dev/null
@@ -0,0 +1,2230 @@
+/*
+ * SH7724 Pinmux
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ *
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on SH7723 Pinmux
+ *  Copyright (C) 2008  Magnus Damm
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/sh7724.h>
+
+enum {
+       PINMUX_RESERVED = 0,
+
+       PINMUX_DATA_BEGIN,
+       PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
+       PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA,
+       PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
+       PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA,
+       PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
+       PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA,
+       PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
+       PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA,
+       PTE7_DATA, PTE6_DATA, PTE5_DATA, PTE4_DATA,
+       PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA,
+       PTF7_DATA, PTF6_DATA, PTF5_DATA, PTF4_DATA,
+       PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA,
+                             PTG5_DATA, PTG4_DATA,
+       PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA,
+       PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
+       PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
+       PTJ7_DATA, PTJ6_DATA, PTJ5_DATA,
+       PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA,
+       PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
+       PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
+       PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+       PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA,
+       PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+       PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
+       PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+       PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA,
+       PTQ7_DATA, PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
+       PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA,
+       PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
+       PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
+                  PTS6_DATA, PTS5_DATA, PTS4_DATA,
+       PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
+       PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
+       PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
+       PTU7_DATA, PTU6_DATA, PTU5_DATA, PTU4_DATA,
+       PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
+       PTV7_DATA, PTV6_DATA, PTV5_DATA, PTV4_DATA,
+       PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA,
+       PTW7_DATA, PTW6_DATA, PTW5_DATA, PTW4_DATA,
+       PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA,
+       PTX7_DATA, PTX6_DATA, PTX5_DATA, PTX4_DATA,
+       PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA,
+       PTY7_DATA, PTY6_DATA, PTY5_DATA, PTY4_DATA,
+       PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA,
+       PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA,
+       PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA,
+       PINMUX_DATA_END,
+
+       PINMUX_INPUT_BEGIN,
+       PTA7_IN, PTA6_IN, PTA5_IN, PTA4_IN,
+       PTA3_IN, PTA2_IN, PTA1_IN, PTA0_IN,
+       PTB7_IN, PTB6_IN, PTB5_IN, PTB4_IN,
+       PTB3_IN, PTB2_IN, PTB1_IN, PTB0_IN,
+       PTC7_IN, PTC6_IN, PTC5_IN, PTC4_IN,
+       PTC3_IN, PTC2_IN, PTC1_IN, PTC0_IN,
+       PTD7_IN, PTD6_IN, PTD5_IN, PTD4_IN,
+       PTD3_IN, PTD2_IN, PTD1_IN, PTD0_IN,
+       PTE7_IN, PTE6_IN, PTE5_IN, PTE4_IN,
+       PTE3_IN, PTE2_IN, PTE1_IN, PTE0_IN,
+       PTF7_IN, PTF6_IN, PTF5_IN, PTF4_IN,
+       PTF3_IN, PTF2_IN, PTF1_IN, PTF0_IN,
+       PTH7_IN, PTH6_IN, PTH5_IN, PTH4_IN,
+       PTH3_IN, PTH2_IN, PTH1_IN, PTH0_IN,
+       PTJ3_IN, PTJ2_IN, PTJ1_IN, PTJ0_IN,
+       PTK7_IN, PTK6_IN, PTK5_IN, PTK4_IN,
+       PTK3_IN, PTK2_IN, PTK1_IN, PTK0_IN,
+       PTL7_IN, PTL6_IN, PTL5_IN, PTL4_IN,
+       PTL3_IN, PTL2_IN, PTL1_IN, PTL0_IN,
+       PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
+       PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
+       PTN7_IN, PTN6_IN, PTN5_IN, PTN4_IN,
+       PTN3_IN, PTN2_IN, PTN1_IN, PTN0_IN,
+       PTQ7_IN, PTQ6_IN, PTQ5_IN, PTQ4_IN,
+       PTQ3_IN, PTQ2_IN, PTQ1_IN, PTQ0_IN,
+       PTR7_IN, PTR6_IN, PTR5_IN, PTR4_IN,
+       PTR3_IN, PTR2_IN, PTR1_IN, PTR0_IN,
+                PTS6_IN, PTS5_IN, PTS4_IN,
+       PTS3_IN, PTS2_IN, PTS1_IN, PTS0_IN,
+       PTT7_IN, PTT6_IN, PTT5_IN, PTT4_IN,
+       PTT3_IN, PTT2_IN, PTT1_IN, PTT0_IN,
+       PTU7_IN, PTU6_IN, PTU5_IN, PTU4_IN,
+       PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
+       PTV7_IN, PTV6_IN, PTV5_IN, PTV4_IN,
+       PTV3_IN, PTV2_IN, PTV1_IN, PTV0_IN,
+       PTW7_IN, PTW6_IN, PTW5_IN, PTW4_IN,
+       PTW3_IN, PTW2_IN, PTW1_IN, PTW0_IN,
+       PTX7_IN, PTX6_IN, PTX5_IN, PTX4_IN,
+       PTX3_IN, PTX2_IN, PTX1_IN, PTX0_IN,
+       PTY7_IN, PTY6_IN, PTY5_IN, PTY4_IN,
+       PTY3_IN, PTY2_IN, PTY1_IN, PTY0_IN,
+       PTZ7_IN, PTZ6_IN, PTZ5_IN, PTZ4_IN,
+       PTZ3_IN, PTZ2_IN, PTZ1_IN, PTZ0_IN,
+       PINMUX_INPUT_END,
+
+       PINMUX_INPUT_PULLUP_BEGIN,
+       PTA7_IN_PU, PTA6_IN_PU, PTA5_IN_PU, PTA4_IN_PU,
+       PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
+       PTB7_IN_PU, PTB6_IN_PU, PTB5_IN_PU, PTB4_IN_PU,
+       PTB3_IN_PU, PTB2_IN_PU, PTB1_IN_PU, PTB0_IN_PU,
+       PTC7_IN_PU, PTC6_IN_PU, PTC5_IN_PU, PTC4_IN_PU,
+       PTC3_IN_PU, PTC2_IN_PU, PTC1_IN_PU, PTC0_IN_PU,
+       PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
+       PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU, PTD0_IN_PU,
+       PTE7_IN_PU, PTE6_IN_PU, PTE5_IN_PU, PTE4_IN_PU,
+       PTE3_IN_PU, PTE2_IN_PU, PTE1_IN_PU, PTE0_IN_PU,
+       PTF7_IN_PU, PTF6_IN_PU, PTF5_IN_PU, PTF4_IN_PU,
+       PTF3_IN_PU, PTF2_IN_PU, PTF1_IN_PU, PTF0_IN_PU,
+       PTH7_IN_PU, PTH6_IN_PU, PTH5_IN_PU, PTH4_IN_PU,
+       PTH3_IN_PU, PTH2_IN_PU, PTH1_IN_PU, PTH0_IN_PU,
+       PTJ3_IN_PU, PTJ2_IN_PU, PTJ1_IN_PU, PTJ0_IN_PU,
+       PTK7_IN_PU, PTK6_IN_PU, PTK5_IN_PU, PTK4_IN_PU,
+       PTK3_IN_PU, PTK2_IN_PU, PTK1_IN_PU, PTK0_IN_PU,
+       PTL7_IN_PU, PTL6_IN_PU, PTL5_IN_PU, PTL4_IN_PU,
+       PTL3_IN_PU, PTL2_IN_PU, PTL1_IN_PU, PTL0_IN_PU,
+       PTM7_IN_PU, PTM6_IN_PU, PTM5_IN_PU, PTM4_IN_PU,
+       PTM3_IN_PU, PTM2_IN_PU, PTM1_IN_PU, PTM0_IN_PU,
+       PTN7_IN_PU, PTN6_IN_PU, PTN5_IN_PU, PTN4_IN_PU,
+       PTN3_IN_PU, PTN2_IN_PU, PTN1_IN_PU, PTN0_IN_PU,
+       PTQ7_IN_PU, PTQ6_IN_PU, PTQ5_IN_PU, PTQ4_IN_PU,
+       PTQ3_IN_PU, PTQ2_IN_PU, PTQ1_IN_PU, PTQ0_IN_PU,
+       PTR7_IN_PU, PTR6_IN_PU, PTR5_IN_PU, PTR4_IN_PU,
+       PTR3_IN_PU, PTR2_IN_PU, PTR1_IN_PU, PTR0_IN_PU,
+                   PTS6_IN_PU, PTS5_IN_PU, PTS4_IN_PU,
+       PTS3_IN_PU, PTS2_IN_PU, PTS1_IN_PU, PTS0_IN_PU,
+       PTT7_IN_PU, PTT6_IN_PU, PTT5_IN_PU, PTT4_IN_PU,
+       PTT3_IN_PU, PTT2_IN_PU, PTT1_IN_PU, PTT0_IN_PU,
+       PTU7_IN_PU, PTU6_IN_PU, PTU5_IN_PU, PTU4_IN_PU,
+       PTU3_IN_PU, PTU2_IN_PU, PTU1_IN_PU, PTU0_IN_PU,
+       PTV7_IN_PU, PTV6_IN_PU, PTV5_IN_PU, PTV4_IN_PU,
+       PTV3_IN_PU, PTV2_IN_PU, PTV1_IN_PU, PTV0_IN_PU,
+       PTW7_IN_PU, PTW6_IN_PU, PTW5_IN_PU, PTW4_IN_PU,
+       PTW3_IN_PU, PTW2_IN_PU, PTW1_IN_PU, PTW0_IN_PU,
+       PTX7_IN_PU, PTX6_IN_PU, PTX5_IN_PU, PTX4_IN_PU,
+       PTX3_IN_PU, PTX2_IN_PU, PTX1_IN_PU, PTX0_IN_PU,
+       PTY7_IN_PU, PTY6_IN_PU, PTY5_IN_PU, PTY4_IN_PU,
+       PTY3_IN_PU, PTY2_IN_PU, PTY1_IN_PU, PTY0_IN_PU,
+       PTZ7_IN_PU, PTZ6_IN_PU, PTZ5_IN_PU, PTZ4_IN_PU,
+       PTZ3_IN_PU, PTZ2_IN_PU, PTZ1_IN_PU, PTZ0_IN_PU,
+       PINMUX_INPUT_PULLUP_END,
+
+       PINMUX_OUTPUT_BEGIN,
+       PTA7_OUT, PTA6_OUT, PTA5_OUT, PTA4_OUT,
+       PTA3_OUT, PTA2_OUT, PTA1_OUT, PTA0_OUT,
+       PTB7_OUT, PTB6_OUT, PTB5_OUT, PTB4_OUT,
+       PTB3_OUT, PTB2_OUT, PTB1_OUT, PTB0_OUT,
+       PTC7_OUT, PTC6_OUT, PTC5_OUT, PTC4_OUT,
+       PTC3_OUT, PTC2_OUT, PTC1_OUT, PTC0_OUT,
+       PTD7_OUT, PTD6_OUT, PTD5_OUT, PTD4_OUT,
+       PTD3_OUT, PTD2_OUT, PTD1_OUT, PTD0_OUT,
+       PTE7_OUT, PTE6_OUT, PTE5_OUT, PTE4_OUT,
+       PTE3_OUT, PTE2_OUT, PTE1_OUT, PTE0_OUT,
+       PTF7_OUT, PTF6_OUT, PTF5_OUT, PTF4_OUT,
+       PTF3_OUT, PTF2_OUT, PTF1_OUT, PTF0_OUT,
+                           PTG5_OUT, PTG4_OUT,
+       PTG3_OUT, PTG2_OUT, PTG1_OUT, PTG0_OUT,
+       PTH7_OUT, PTH6_OUT, PTH5_OUT, PTH4_OUT,
+       PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
+       PTJ7_OUT, PTJ6_OUT, PTJ5_OUT,
+       PTJ3_OUT, PTJ2_OUT, PTJ1_OUT, PTJ0_OUT,
+       PTK7_OUT, PTK6_OUT, PTK5_OUT, PTK4_OUT,
+       PTK3_OUT, PTK2_OUT, PTK1_OUT, PTK0_OUT,
+       PTL7_OUT, PTL6_OUT, PTL5_OUT, PTL4_OUT,
+       PTL3_OUT, PTL2_OUT, PTL1_OUT, PTL0_OUT,
+       PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
+       PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
+       PTN7_OUT, PTN6_OUT, PTN5_OUT, PTN4_OUT,
+       PTN3_OUT, PTN2_OUT, PTN1_OUT, PTN0_OUT,
+       PTQ7_OUT, PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
+       PTQ3_OUT, PTQ2_OUT, PTQ1_OUT, PTQ0_OUT,
+       PTR7_OUT, PTR6_OUT, PTR5_OUT, PTR4_OUT,
+                           PTR1_OUT, PTR0_OUT,
+                 PTS6_OUT, PTS5_OUT, PTS4_OUT,
+       PTS3_OUT, PTS2_OUT, PTS1_OUT, PTS0_OUT,
+       PTT7_OUT, PTT6_OUT, PTT5_OUT, PTT4_OUT,
+       PTT3_OUT, PTT2_OUT, PTT1_OUT, PTT0_OUT,
+       PTU7_OUT, PTU6_OUT, PTU5_OUT, PTU4_OUT,
+       PTU3_OUT, PTU2_OUT, PTU1_OUT, PTU0_OUT,
+       PTV7_OUT, PTV6_OUT, PTV5_OUT, PTV4_OUT,
+       PTV3_OUT, PTV2_OUT, PTV1_OUT, PTV0_OUT,
+       PTW7_OUT, PTW6_OUT, PTW5_OUT, PTW4_OUT,
+       PTW3_OUT, PTW2_OUT, PTW1_OUT, PTW0_OUT,
+       PTX7_OUT, PTX6_OUT, PTX5_OUT, PTX4_OUT,
+       PTX3_OUT, PTX2_OUT, PTX1_OUT, PTX0_OUT,
+       PTY7_OUT, PTY6_OUT, PTY5_OUT, PTY4_OUT,
+       PTY3_OUT, PTY2_OUT, PTY1_OUT, PTY0_OUT,
+       PTZ7_OUT, PTZ6_OUT, PTZ5_OUT, PTZ4_OUT,
+       PTZ3_OUT, PTZ2_OUT, PTZ1_OUT, PTZ0_OUT,
+       PINMUX_OUTPUT_END,
+
+       PINMUX_FUNCTION_BEGIN,
+       PTA7_FN, PTA6_FN, PTA5_FN, PTA4_FN,
+       PTA3_FN, PTA2_FN, PTA1_FN, PTA0_FN,
+       PTB7_FN, PTB6_FN, PTB5_FN, PTB4_FN,
+       PTB3_FN, PTB2_FN, PTB1_FN, PTB0_FN,
+       PTC7_FN, PTC6_FN, PTC5_FN, PTC4_FN,
+       PTC3_FN, PTC2_FN, PTC1_FN, PTC0_FN,
+       PTD7_FN, PTD6_FN, PTD5_FN, PTD4_FN,
+       PTD3_FN, PTD2_FN, PTD1_FN, PTD0_FN,
+       PTE7_FN, PTE6_FN, PTE5_FN, PTE4_FN,
+       PTE3_FN, PTE2_FN, PTE1_FN, PTE0_FN,
+       PTF7_FN, PTF6_FN, PTF5_FN, PTF4_FN,
+       PTF3_FN, PTF2_FN, PTF1_FN, PTF0_FN,
+                         PTG5_FN, PTG4_FN,
+       PTG3_FN, PTG2_FN, PTG1_FN, PTG0_FN,
+       PTH7_FN, PTH6_FN, PTH5_FN, PTH4_FN,
+       PTH3_FN, PTH2_FN, PTH1_FN, PTH0_FN,
+       PTJ7_FN, PTJ6_FN, PTJ5_FN,
+       PTJ3_FN, PTJ2_FN, PTJ1_FN, PTJ0_FN,
+       PTK7_FN, PTK6_FN, PTK5_FN, PTK4_FN,
+       PTK3_FN, PTK2_FN, PTK1_FN, PTK0_FN,
+       PTL7_FN, PTL6_FN, PTL5_FN, PTL4_FN,
+       PTL3_FN, PTL2_FN, PTL1_FN, PTL0_FN,
+       PTM7_FN, PTM6_FN, PTM5_FN, PTM4_FN,
+       PTM3_FN, PTM2_FN, PTM1_FN, PTM0_FN,
+       PTN7_FN, PTN6_FN, PTN5_FN, PTN4_FN,
+       PTN3_FN, PTN2_FN, PTN1_FN, PTN0_FN,
+       PTQ7_FN, PTQ6_FN, PTQ5_FN, PTQ4_FN,
+       PTQ3_FN, PTQ2_FN, PTQ1_FN, PTQ0_FN,
+       PTR7_FN, PTR6_FN, PTR5_FN, PTR4_FN,
+       PTR3_FN, PTR2_FN, PTR1_FN, PTR0_FN,
+                PTS6_FN, PTS5_FN, PTS4_FN,
+       PTS3_FN, PTS2_FN, PTS1_FN, PTS0_FN,
+       PTT7_FN, PTT6_FN, PTT5_FN, PTT4_FN,
+       PTT3_FN, PTT2_FN, PTT1_FN, PTT0_FN,
+       PTU7_FN, PTU6_FN, PTU5_FN, PTU4_FN,
+       PTU3_FN, PTU2_FN, PTU1_FN, PTU0_FN,
+       PTV7_FN, PTV6_FN, PTV5_FN, PTV4_FN,
+       PTV3_FN, PTV2_FN, PTV1_FN, PTV0_FN,
+       PTW7_FN, PTW6_FN, PTW5_FN, PTW4_FN,
+       PTW3_FN, PTW2_FN, PTW1_FN, PTW0_FN,
+       PTX7_FN, PTX6_FN, PTX5_FN, PTX4_FN,
+       PTX3_FN, PTX2_FN, PTX1_FN, PTX0_FN,
+       PTY7_FN, PTY6_FN, PTY5_FN, PTY4_FN,
+       PTY3_FN, PTY2_FN, PTY1_FN, PTY0_FN,
+       PTZ7_FN, PTZ6_FN, PTZ5_FN, PTZ4_FN,
+       PTZ3_FN, PTZ2_FN, PTZ1_FN, PTZ0_FN,
+
+
+       PSA15_0, PSA15_1,
+       PSA14_0, PSA14_1,
+       PSA13_0, PSA13_1,
+       PSA12_0, PSA12_1,
+       PSA10_0, PSA10_1,
+       PSA9_0,  PSA9_1,
+       PSA8_0,  PSA8_1,
+       PSA7_0,  PSA7_1,
+       PSA6_0,  PSA6_1,
+       PSA5_0,  PSA5_1,
+       PSA3_0,  PSA3_1,
+       PSA2_0,  PSA2_1,
+       PSA1_0,  PSA1_1,
+       PSA0_0,  PSA0_1,
+
+       PSB14_0, PSB14_1,
+       PSB13_0, PSB13_1,
+       PSB12_0, PSB12_1,
+       PSB11_0, PSB11_1,
+       PSB10_0, PSB10_1,
+       PSB9_0,  PSB9_1,
+       PSB8_0,  PSB8_1,
+       PSB7_0,  PSB7_1,
+       PSB6_0,  PSB6_1,
+       PSB5_0,  PSB5_1,
+       PSB4_0,  PSB4_1,
+       PSB3_0,  PSB3_1,
+       PSB2_0,  PSB2_1,
+       PSB1_0,  PSB1_1,
+       PSB0_0,  PSB0_1,
+
+       PSC15_0, PSC15_1,
+       PSC14_0, PSC14_1,
+       PSC13_0, PSC13_1,
+       PSC12_0, PSC12_1,
+       PSC11_0, PSC11_1,
+       PSC10_0, PSC10_1,
+       PSC9_0,  PSC9_1,
+       PSC8_0,  PSC8_1,
+       PSC7_0,  PSC7_1,
+       PSC6_0,  PSC6_1,
+       PSC5_0,  PSC5_1,
+       PSC4_0,  PSC4_1,
+       PSC2_0,  PSC2_1,
+       PSC1_0,  PSC1_1,
+       PSC0_0,  PSC0_1,
+
+       PSD15_0, PSD15_1,
+       PSD14_0, PSD14_1,
+       PSD13_0, PSD13_1,
+       PSD12_0, PSD12_1,
+       PSD11_0, PSD11_1,
+       PSD10_0, PSD10_1,
+       PSD9_0,  PSD9_1,
+       PSD8_0,  PSD8_1,
+       PSD7_0,  PSD7_1,
+       PSD6_0,  PSD6_1,
+       PSD5_0,  PSD5_1,
+       PSD4_0,  PSD4_1,
+       PSD3_0,  PSD3_1,
+       PSD2_0,  PSD2_1,
+       PSD1_0,  PSD1_1,
+       PSD0_0,  PSD0_1,
+
+       PSE15_0, PSE15_1,
+       PSE14_0, PSE14_1,
+       PSE13_0, PSE13_1,
+       PSE12_0, PSE12_1,
+       PSE11_0, PSE11_1,
+       PSE10_0, PSE10_1,
+       PSE9_0,  PSE9_1,
+       PSE8_0,  PSE8_1,
+       PSE7_0,  PSE7_1,
+       PSE6_0,  PSE6_1,
+       PSE5_0,  PSE5_1,
+       PSE4_0,  PSE4_1,
+       PSE3_0,  PSE3_1,
+       PSE2_0,  PSE2_1,
+       PSE1_0,  PSE1_1,
+       PSE0_0,  PSE0_1,
+       PINMUX_FUNCTION_END,
+
+       PINMUX_MARK_BEGIN,
+       /*PTA*/
+       D23_MARK,       KEYOUT2_MARK,           IDED15_MARK,
+       D22_MARK,       KEYOUT1_MARK,           IDED14_MARK,
+       D21_MARK,       KEYOUT0_MARK,           IDED13_MARK,
+       D20_MARK,       KEYIN4_MARK,            IDED12_MARK,
+       D19_MARK,       KEYIN3_MARK,            IDED11_MARK,
+       D18_MARK,       KEYIN2_MARK,            IDED10_MARK,
+       D17_MARK,       KEYIN1_MARK,            IDED9_MARK,
+       D16_MARK,       KEYIN0_MARK,            IDED8_MARK,
+
+       /*PTB*/
+       D31_MARK,       TPUTO1_MARK,            IDEA1_MARK,
+       D30_MARK,       TPUTO0_MARK,            IDEA0_MARK,
+       D29_MARK,                               IODREQ_MARK,
+       D28_MARK,                               IDECS0_MARK,
+       D27_MARK,                               IDECS1_MARK,
+       D26_MARK,       KEYOUT5_IN5_MARK,       IDEIORD_MARK,
+       D25_MARK,       KEYOUT4_IN6_MARK,       IDEIOWR_MARK,
+       D24_MARK,       KEYOUT3_MARK,           IDEINT_MARK,
+
+       /*PTC*/
+       LCDD7_MARK,
+       LCDD6_MARK,
+       LCDD5_MARK,
+       LCDD4_MARK,
+       LCDD3_MARK,
+       LCDD2_MARK,
+       LCDD1_MARK,
+       LCDD0_MARK,
+
+       /*PTD*/
+       LCDD15_MARK,
+       LCDD14_MARK,
+       LCDD13_MARK,
+       LCDD12_MARK,
+       LCDD11_MARK,
+       LCDD10_MARK,
+       LCDD9_MARK,
+       LCDD8_MARK,
+
+       /*PTE*/
+       FSIMCKB_MARK,
+       FSIMCKA_MARK,
+       LCDD21_MARK,    SCIF2_L_TXD_MARK,
+       LCDD20_MARK,    SCIF4_SCK_MARK,
+       LCDD19_MARK,    SCIF4_RXD_MARK,
+       LCDD18_MARK,    SCIF4_TXD_MARK,
+       LCDD17_MARK,
+       LCDD16_MARK,
+
+       /*PTF*/
+       LCDVSYN_MARK,
+       LCDDISP_MARK,   LCDRS_MARK,
+       LCDHSYN_MARK,   LCDCS_MARK,
+       LCDDON_MARK,
+       LCDDCK_MARK,    LCDWR_MARK,
+       LCDVEPWC_MARK,  SCIF0_TXD_MARK,
+       LCDD23_MARK,    SCIF2_L_SCK_MARK,
+       LCDD22_MARK,    SCIF2_L_RXD_MARK,
+
+       /*PTG*/
+       AUDCK_MARK,
+       AUDSYNC_MARK,
+       AUDATA3_MARK,
+       AUDATA2_MARK,
+       AUDATA1_MARK,
+       AUDATA0_MARK,
+
+       /*PTH*/
+       VIO0_VD_MARK,
+       VIO0_CLK_MARK,
+       VIO0_D7_MARK,
+       VIO0_D6_MARK,
+       VIO0_D5_MARK,
+       VIO0_D4_MARK,
+       VIO0_D3_MARK,
+       VIO0_D2_MARK,
+
+       /*PTJ*/
+       PDSTATUS_MARK,
+       STATUS2_MARK,
+       STATUS0_MARK,
+       A25_MARK,               BS_MARK,
+       A24_MARK,
+       A23_MARK,
+       A22_MARK,
+
+       /*PTK*/
+       VIO1_D5_MARK,   VIO0_D13_MARK,  IDED5_MARK,
+       VIO1_D4_MARK,   VIO0_D12_MARK,  IDED4_MARK,
+       VIO1_D3_MARK,   VIO0_D11_MARK,  IDED3_MARK,
+       VIO1_D2_MARK,   VIO0_D10_MARK,  IDED2_MARK,
+       VIO1_D1_MARK,   VIO0_D9_MARK,   IDED1_MARK,
+       VIO1_D0_MARK,   VIO0_D8_MARK,   IDED0_MARK,
+       VIO0_FLD_MARK,
+       VIO0_HD_MARK,
+
+       /*PTL*/
+       DV_D5_MARK,     SCIF3_V_SCK_MARK,       RMII_RXD0_MARK,
+       DV_D4_MARK,     SCIF3_V_RXD_MARK,       RMII_RXD1_MARK,
+       DV_D3_MARK,     SCIF3_V_TXD_MARK,       RMII_REF_CLK_MARK,
+       DV_D2_MARK,     SCIF1_SCK_MARK,         RMII_TX_EN_MARK,
+       DV_D1_MARK,     SCIF1_RXD_MARK,         RMII_TXD0_MARK,
+       DV_D0_MARK,     SCIF1_TXD_MARK,         RMII_TXD1_MARK,
+       DV_D15_MARK,
+       DV_D14_MARK,    MSIOF0_MCK_MARK,
+
+       /*PTM*/
+       DV_D13_MARK,    MSIOF0_TSCK_MARK,
+       DV_D12_MARK,    MSIOF0_RXD_MARK,
+       DV_D11_MARK,    MSIOF0_TXD_MARK,
+       DV_D10_MARK,    MSIOF0_TSYNC_MARK,
+       DV_D9_MARK,     MSIOF0_SS1_MARK,        MSIOF0_RSCK_MARK,
+       DV_D8_MARK,     MSIOF0_SS2_MARK,        MSIOF0_RSYNC_MARK,
+       LCDVCPWC_MARK,  SCIF0_RXD_MARK,
+       LCDRD_MARK,     SCIF0_SCK_MARK,
+
+       /*PTN*/
+       VIO0_D1_MARK,
+       VIO0_D0_MARK,
+       DV_CLKI_MARK,
+       DV_CLK_MARK,    SCIF2_V_SCK_MARK,
+       DV_VSYNC_MARK,  SCIF2_V_RXD_MARK,
+       DV_HSYNC_MARK,  SCIF2_V_TXD_MARK,
+       DV_D7_MARK,     SCIF3_V_CTS_MARK,       RMII_RX_ER_MARK,
+       DV_D6_MARK,     SCIF3_V_RTS_MARK,       RMII_CRS_DV_MARK,
+
+       /*PTQ*/
+       D7_MARK,
+       D6_MARK,
+       D5_MARK,
+       D4_MARK,
+       D3_MARK,
+       D2_MARK,
+       D1_MARK,
+       D0_MARK,
+
+       /*PTR*/
+       CS6B_CE1B_MARK,
+       CS6A_CE2B_MARK,
+       CS5B_CE1A_MARK,
+       CS5A_CE2A_MARK,
+       IOIS16_MARK,            LCDLCLK_MARK,
+       WAIT_MARK,
+       WE3_ICIOWR_MARK,        TPUTO3_MARK,    TPUTI3_MARK,
+       WE2_ICIORD_MARK,        TPUTO2_MARK,    IDEA2_MARK,
+
+       /*PTS*/
+       VIO_CKO_MARK,
+       VIO1_FLD_MARK,  TPUTI2_MARK,            IDEIORDY_MARK,
+       VIO1_HD_MARK,   SCIF5_SCK_MARK,
+       VIO1_VD_MARK,   SCIF5_RXD_MARK,
+       VIO1_CLK_MARK,  SCIF5_TXD_MARK,
+       VIO1_D7_MARK,   VIO0_D15_MARK,          IDED7_MARK,
+       VIO1_D6_MARK,   VIO0_D14_MARK,          IDED6_MARK,
+
+       /*PTT*/
+       D15_MARK,
+       D14_MARK,
+       D13_MARK,
+       D12_MARK,
+       D11_MARK,
+       D10_MARK,
+       D9_MARK,
+       D8_MARK,
+
+       /*PTU*/
+       DMAC_DACK0_MARK,
+       DMAC_DREQ0_MARK,
+       FSIOASD_MARK,
+       FSIIABCK_MARK,
+       FSIIALRCK_MARK,
+       FSIOABCK_MARK,
+       FSIOALRCK_MARK,
+       CLKAUDIOAO_MARK,
+
+       /*PTV*/
+       FSIIBSD_MARK,           MSIOF1_SS2_MARK,        MSIOF1_RSYNC_MARK,
+       FSIOBSD_MARK,           MSIOF1_SS1_MARK,        MSIOF1_RSCK_MARK,
+       FSIIBBCK_MARK,          MSIOF1_RXD_MARK,
+       FSIIBLRCK_MARK,         MSIOF1_TSYNC_MARK,
+       FSIOBBCK_MARK,          MSIOF1_TSCK_MARK,
+       FSIOBLRCK_MARK,         MSIOF1_TXD_MARK,
+       CLKAUDIOBO_MARK,        MSIOF1_MCK_MARK,
+       FSIIASD_MARK,
+
+       /*PTW*/
+       MMC_D7_MARK,            SDHI1CD_MARK,           IODACK_MARK,
+       MMC_D6_MARK,            SDHI1WP_MARK,           IDERST_MARK,
+       MMC_D5_MARK,            SDHI1D3_MARK,           EXBUF_ENB_MARK,
+       MMC_D4_MARK,            SDHI1D2_MARK,           DIRECTION_MARK,
+       MMC_D3_MARK,            SDHI1D1_MARK,
+       MMC_D2_MARK,            SDHI1D0_MARK,
+       MMC_D1_MARK,            SDHI1CMD_MARK,
+       MMC_D0_MARK,            SDHI1CLK_MARK,
+
+       /*PTX*/
+       DMAC_DACK1_MARK,        IRDA_OUT_MARK,
+       DMAC_DREQ1_MARK,        IRDA_IN_MARK,
+       TSIF_TS0_SDAT_MARK,                             LNKSTA_MARK,
+       TSIF_TS0_SCK_MARK,                              MDIO_MARK,
+       TSIF_TS0_SDEN_MARK,                             MDC_MARK,
+       TSIF_TS0_SPSYNC_MARK,
+       MMC_CLK_MARK,
+       MMC_CMD_MARK,
+
+       /*PTY*/
+       SDHI0CD_MARK,
+       SDHI0WP_MARK,
+       SDHI0D3_MARK,
+       SDHI0D2_MARK,
+       SDHI0D1_MARK,
+       SDHI0D0_MARK,
+       SDHI0CMD_MARK,
+       SDHI0CLK_MARK,
+
+       /*PTZ*/
+       INTC_IRQ7_MARK,         SCIF3_I_CTS_MARK,
+       INTC_IRQ6_MARK,         SCIF3_I_RTS_MARK,
+       INTC_IRQ5_MARK,         SCIF3_I_SCK_MARK,
+       INTC_IRQ4_MARK,         SCIF3_I_RXD_MARK,
+       INTC_IRQ3_MARK,         SCIF3_I_TXD_MARK,
+       INTC_IRQ2_MARK,
+       INTC_IRQ1_MARK,
+       INTC_IRQ0_MARK,
+       PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+       /* PTA GPIO */
+       PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT, PTA7_IN_PU),
+       PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT, PTA6_IN_PU),
+       PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT, PTA5_IN_PU),
+       PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT, PTA4_IN_PU),
+       PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT, PTA3_IN_PU),
+       PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT, PTA2_IN_PU),
+       PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT, PTA1_IN_PU),
+       PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT, PTA0_IN_PU),
+
+       /* PTB GPIO */
+       PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT, PTB7_IN_PU),
+       PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT, PTB6_IN_PU),
+       PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT, PTB5_IN_PU),
+       PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT, PTB4_IN_PU),
+       PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT, PTB3_IN_PU),
+       PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT, PTB2_IN_PU),
+       PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT, PTB1_IN_PU),
+       PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT, PTB0_IN_PU),
+
+       /* PTC GPIO */
+       PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_OUT, PTC7_IN_PU),
+       PINMUX_DATA(PTC6_DATA, PTC6_IN, PTC6_OUT, PTC6_IN_PU),
+       PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_OUT, PTC5_IN_PU),
+       PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT, PTC4_IN_PU),
+       PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT, PTC3_IN_PU),
+       PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT, PTC2_IN_PU),
+       PINMUX_DATA(PTC1_DATA, PTC1_IN, PTC1_OUT, PTC1_IN_PU),
+       PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT, PTC0_IN_PU),
+
+       /* PTD GPIO */
+       PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_OUT, PTD7_IN_PU),
+       PINMUX_DATA(PTD6_DATA, PTD6_IN, PTD6_OUT, PTD6_IN_PU),
+       PINMUX_DATA(PTD5_DATA, PTD5_IN, PTD5_OUT, PTD5_IN_PU),
+       PINMUX_DATA(PTD4_DATA, PTD4_IN, PTD4_OUT, PTD4_IN_PU),
+       PINMUX_DATA(PTD3_DATA, PTD3_IN, PTD3_OUT, PTD3_IN_PU),
+       PINMUX_DATA(PTD2_DATA, PTD2_IN, PTD2_OUT, PTD2_IN_PU),
+       PINMUX_DATA(PTD1_DATA, PTD1_IN, PTD1_OUT, PTD1_IN_PU),
+       PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT, PTD0_IN_PU),
+
+       /* PTE GPIO */
+       PINMUX_DATA(PTE7_DATA, PTE7_IN, PTE7_OUT, PTE7_IN_PU),
+       PINMUX_DATA(PTE6_DATA, PTE6_IN, PTE6_OUT, PTE6_IN_PU),
+       PINMUX_DATA(PTE5_DATA, PTE5_IN, PTE5_OUT, PTE5_IN_PU),
+       PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT, PTE4_IN_PU),
+       PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT, PTE3_IN_PU),
+       PINMUX_DATA(PTE2_DATA, PTE2_IN, PTE2_OUT, PTE2_IN_PU),
+       PINMUX_DATA(PTE1_DATA, PTE1_IN, PTE1_OUT, PTE1_IN_PU),
+       PINMUX_DATA(PTE0_DATA, PTE0_IN, PTE0_OUT, PTE0_IN_PU),
+
+       /* PTF GPIO */
+       PINMUX_DATA(PTF7_DATA, PTF7_IN, PTF7_OUT, PTF7_IN_PU),
+       PINMUX_DATA(PTF6_DATA, PTF6_IN, PTF6_OUT, PTF6_IN_PU),
+       PINMUX_DATA(PTF5_DATA, PTF5_IN, PTF5_OUT, PTF5_IN_PU),
+       PINMUX_DATA(PTF4_DATA, PTF4_IN, PTF4_OUT, PTF4_IN_PU),
+       PINMUX_DATA(PTF3_DATA, PTF3_IN, PTF3_OUT, PTF3_IN_PU),
+       PINMUX_DATA(PTF2_DATA, PTF2_IN, PTF2_OUT, PTF2_IN_PU),
+       PINMUX_DATA(PTF1_DATA, PTF1_IN, PTF1_OUT, PTF1_IN_PU),
+       PINMUX_DATA(PTF0_DATA, PTF0_IN, PTF0_OUT, PTF0_IN_PU),
+
+       /* PTG GPIO */
+       PINMUX_DATA(PTG5_DATA, PTG5_OUT),
+       PINMUX_DATA(PTG4_DATA, PTG4_OUT),
+       PINMUX_DATA(PTG3_DATA, PTG3_OUT),
+       PINMUX_DATA(PTG2_DATA, PTG2_OUT),
+       PINMUX_DATA(PTG1_DATA, PTG1_OUT),
+       PINMUX_DATA(PTG0_DATA, PTG0_OUT),
+
+       /* PTH GPIO */
+       PINMUX_DATA(PTH7_DATA, PTH7_IN, PTH7_OUT, PTH7_IN_PU),
+       PINMUX_DATA(PTH6_DATA, PTH6_IN, PTH6_OUT, PTH6_IN_PU),
+       PINMUX_DATA(PTH5_DATA, PTH5_IN, PTH5_OUT, PTH5_IN_PU),
+       PINMUX_DATA(PTH4_DATA, PTH4_IN, PTH4_OUT, PTH4_IN_PU),
+       PINMUX_DATA(PTH3_DATA, PTH3_IN, PTH3_OUT, PTH3_IN_PU),
+       PINMUX_DATA(PTH2_DATA, PTH2_IN, PTH2_OUT, PTH2_IN_PU),
+       PINMUX_DATA(PTH1_DATA, PTH1_IN, PTH1_OUT, PTH1_IN_PU),
+       PINMUX_DATA(PTH0_DATA, PTH0_IN, PTH0_OUT, PTH0_IN_PU),
+
+       /* PTJ GPIO */
+       PINMUX_DATA(PTJ7_DATA, PTJ7_OUT),
+       PINMUX_DATA(PTJ6_DATA, PTJ6_OUT),
+       PINMUX_DATA(PTJ5_DATA, PTJ5_OUT),
+       PINMUX_DATA(PTJ3_DATA, PTJ3_IN, PTJ3_OUT, PTJ3_IN_PU),
+       PINMUX_DATA(PTJ2_DATA, PTJ2_IN, PTJ2_OUT, PTJ2_IN_PU),
+       PINMUX_DATA(PTJ1_DATA, PTJ1_IN, PTJ1_OUT, PTJ1_IN_PU),
+       PINMUX_DATA(PTJ0_DATA, PTJ0_IN, PTJ0_OUT, PTJ0_IN_PU),
+
+       /* PTK GPIO */
+       PINMUX_DATA(PTK7_DATA, PTK7_IN, PTK7_OUT, PTK7_IN_PU),
+       PINMUX_DATA(PTK6_DATA, PTK6_IN, PTK6_OUT, PTK6_IN_PU),
+       PINMUX_DATA(PTK5_DATA, PTK5_IN, PTK5_OUT, PTK5_IN_PU),
+       PINMUX_DATA(PTK4_DATA, PTK4_IN, PTK4_OUT, PTK4_IN_PU),
+       PINMUX_DATA(PTK3_DATA, PTK3_IN, PTK3_OUT, PTK3_IN_PU),
+       PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_OUT, PTK2_IN_PU),
+       PINMUX_DATA(PTK1_DATA, PTK1_IN, PTK1_OUT, PTK1_IN_PU),
+       PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT, PTK0_IN_PU),
+
+       /* PTL GPIO */
+       PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT, PTL7_IN_PU),
+       PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT, PTL6_IN_PU),
+       PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT, PTL5_IN_PU),
+       PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT, PTL4_IN_PU),
+       PINMUX_DATA(PTL3_DATA, PTL3_IN, PTL3_OUT, PTL3_IN_PU),
+       PINMUX_DATA(PTL2_DATA, PTL2_IN, PTL2_OUT, PTL2_IN_PU),
+       PINMUX_DATA(PTL1_DATA, PTL1_IN, PTL1_OUT, PTL1_IN_PU),
+       PINMUX_DATA(PTL0_DATA, PTL0_IN, PTL0_OUT, PTL0_IN_PU),
+
+       /* PTM GPIO */
+       PINMUX_DATA(PTM7_DATA, PTM7_IN, PTM7_OUT, PTM7_IN_PU),
+       PINMUX_DATA(PTM6_DATA, PTM6_IN, PTM6_OUT, PTM6_IN_PU),
+       PINMUX_DATA(PTM5_DATA, PTM5_IN, PTM5_OUT, PTM5_IN_PU),
+       PINMUX_DATA(PTM4_DATA, PTM4_IN, PTM4_OUT, PTM4_IN_PU),
+       PINMUX_DATA(PTM3_DATA, PTM3_IN, PTM3_OUT, PTM3_IN_PU),
+       PINMUX_DATA(PTM2_DATA, PTM2_IN, PTM2_OUT, PTM2_IN_PU),
+       PINMUX_DATA(PTM1_DATA, PTM1_IN, PTM1_OUT, PTM1_IN_PU),
+       PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT, PTM0_IN_PU),
+
+       /* PTN GPIO */
+       PINMUX_DATA(PTN7_DATA, PTN7_IN, PTN7_OUT, PTN7_IN_PU),
+       PINMUX_DATA(PTN6_DATA, PTN6_IN, PTN6_OUT, PTN6_IN_PU),
+       PINMUX_DATA(PTN5_DATA, PTN5_IN, PTN5_OUT, PTN5_IN_PU),
+       PINMUX_DATA(PTN4_DATA, PTN4_IN, PTN4_OUT, PTN4_IN_PU),
+       PINMUX_DATA(PTN3_DATA, PTN3_IN, PTN3_OUT, PTN3_IN_PU),
+       PINMUX_DATA(PTN2_DATA, PTN2_IN, PTN2_OUT, PTN2_IN_PU),
+       PINMUX_DATA(PTN1_DATA, PTN1_IN, PTN1_OUT, PTN1_IN_PU),
+       PINMUX_DATA(PTN0_DATA, PTN0_IN, PTN0_OUT, PTN0_IN_PU),
+
+       /* PTQ GPIO */
+       PINMUX_DATA(PTQ7_DATA, PTQ7_IN, PTQ7_OUT, PTQ7_IN_PU),
+       PINMUX_DATA(PTQ6_DATA, PTQ6_IN, PTQ6_OUT, PTQ6_IN_PU),
+       PINMUX_DATA(PTQ5_DATA, PTQ5_IN, PTQ5_OUT, PTQ5_IN_PU),
+       PINMUX_DATA(PTQ4_DATA, PTQ4_IN, PTQ4_OUT, PTQ4_IN_PU),
+       PINMUX_DATA(PTQ3_DATA, PTQ3_IN, PTQ3_OUT, PTQ3_IN_PU),
+       PINMUX_DATA(PTQ2_DATA, PTQ2_IN, PTQ2_OUT, PTQ2_IN_PU),
+       PINMUX_DATA(PTQ1_DATA, PTQ1_IN, PTQ1_OUT, PTQ1_IN_PU),
+       PINMUX_DATA(PTQ0_DATA, PTQ0_IN, PTQ0_OUT, PTQ0_IN_PU),
+
+       /* PTR GPIO */
+       PINMUX_DATA(PTR7_DATA, PTR7_IN, PTR7_OUT, PTR7_IN_PU),
+       PINMUX_DATA(PTR6_DATA, PTR6_IN, PTR6_OUT, PTR6_IN_PU),
+       PINMUX_DATA(PTR5_DATA, PTR5_IN, PTR5_OUT, PTR5_IN_PU),
+       PINMUX_DATA(PTR4_DATA, PTR4_IN, PTR4_OUT, PTR4_IN_PU),
+       PINMUX_DATA(PTR3_DATA, PTR3_IN,           PTR3_IN_PU),
+       PINMUX_DATA(PTR2_DATA, PTR2_IN,           PTR2_IN_PU),
+       PINMUX_DATA(PTR1_DATA, PTR1_IN, PTR1_OUT, PTR1_IN_PU),
+       PINMUX_DATA(PTR0_DATA, PTR0_IN, PTR0_OUT, PTR0_IN_PU),
+
+       /* PTS GPIO */
+       PINMUX_DATA(PTS6_DATA, PTS6_IN, PTS6_OUT, PTS6_IN_PU),
+       PINMUX_DATA(PTS5_DATA, PTS5_IN, PTS5_OUT, PTS5_IN_PU),
+       PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_OUT, PTS4_IN_PU),
+       PINMUX_DATA(PTS3_DATA, PTS3_IN, PTS3_OUT, PTS3_IN_PU),
+       PINMUX_DATA(PTS2_DATA, PTS2_IN, PTS2_OUT, PTS2_IN_PU),
+       PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_OUT, PTS1_IN_PU),
+       PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT, PTS0_IN_PU),
+
+       /* PTT GPIO */
+       PINMUX_DATA(PTT7_DATA, PTT7_IN, PTT7_OUT, PTT7_IN_PU),
+       PINMUX_DATA(PTT6_DATA, PTT6_IN, PTT6_OUT, PTT6_IN_PU),
+       PINMUX_DATA(PTT5_DATA, PTT5_IN, PTT5_OUT, PTT5_IN_PU),
+       PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT, PTT4_IN_PU),
+       PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT, PTT3_IN_PU),
+       PINMUX_DATA(PTT2_DATA, PTT2_IN, PTT2_OUT, PTT2_IN_PU),
+       PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_OUT, PTT1_IN_PU),
+       PINMUX_DATA(PTT0_DATA, PTT0_IN, PTT0_OUT, PTT0_IN_PU),
+
+       /* PTU GPIO */
+       PINMUX_DATA(PTU7_DATA, PTU7_IN, PTU7_OUT, PTU7_IN_PU),
+       PINMUX_DATA(PTU6_DATA, PTU6_IN, PTU6_OUT, PTU6_IN_PU),
+       PINMUX_DATA(PTU5_DATA, PTU5_IN, PTU5_OUT, PTU5_IN_PU),
+       PINMUX_DATA(PTU4_DATA, PTU4_IN, PTU4_OUT, PTU4_IN_PU),
+       PINMUX_DATA(PTU3_DATA, PTU3_IN, PTU3_OUT, PTU3_IN_PU),
+       PINMUX_DATA(PTU2_DATA, PTU2_IN, PTU2_OUT, PTU2_IN_PU),
+       PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_OUT, PTU1_IN_PU),
+       PINMUX_DATA(PTU0_DATA, PTU0_IN, PTU0_OUT, PTU0_IN_PU),
+
+       /* PTV GPIO */
+       PINMUX_DATA(PTV7_DATA, PTV7_IN, PTV7_OUT, PTV7_IN_PU),
+       PINMUX_DATA(PTV6_DATA, PTV6_IN, PTV6_OUT, PTV6_IN_PU),
+       PINMUX_DATA(PTV5_DATA, PTV5_IN, PTV5_OUT, PTV5_IN_PU),
+       PINMUX_DATA(PTV4_DATA, PTV4_IN, PTV4_OUT, PTV4_IN_PU),
+       PINMUX_DATA(PTV3_DATA, PTV3_IN, PTV3_OUT, PTV3_IN_PU),
+       PINMUX_DATA(PTV2_DATA, PTV2_IN, PTV2_OUT, PTV2_IN_PU),
+       PINMUX_DATA(PTV1_DATA, PTV1_IN, PTV1_OUT, PTV1_IN_PU),
+       PINMUX_DATA(PTV0_DATA, PTV0_IN, PTV0_OUT, PTV0_IN_PU),
+
+       /* PTW GPIO */
+       PINMUX_DATA(PTW7_DATA, PTW7_IN, PTW7_OUT, PTW7_IN_PU),
+       PINMUX_DATA(PTW6_DATA, PTW6_IN, PTW6_OUT, PTW6_IN_PU),
+       PINMUX_DATA(PTW5_DATA, PTW5_IN, PTW5_OUT, PTW5_IN_PU),
+       PINMUX_DATA(PTW4_DATA, PTW4_IN, PTW4_OUT, PTW4_IN_PU),
+       PINMUX_DATA(PTW3_DATA, PTW3_IN, PTW3_OUT, PTW3_IN_PU),
+       PINMUX_DATA(PTW2_DATA, PTW2_IN, PTW2_OUT, PTW2_IN_PU),
+       PINMUX_DATA(PTW1_DATA, PTW1_IN, PTW1_OUT, PTW1_IN_PU),
+       PINMUX_DATA(PTW0_DATA, PTW0_IN, PTW0_OUT, PTW0_IN_PU),
+
+       /* PTX GPIO */
+       PINMUX_DATA(PTX7_DATA, PTX7_IN, PTX7_OUT, PTX7_IN_PU),
+       PINMUX_DATA(PTX6_DATA, PTX6_IN, PTX6_OUT, PTX6_IN_PU),
+       PINMUX_DATA(PTX5_DATA, PTX5_IN, PTX5_OUT, PTX5_IN_PU),
+       PINMUX_DATA(PTX4_DATA, PTX4_IN, PTX4_OUT, PTX4_IN_PU),
+       PINMUX_DATA(PTX3_DATA, PTX3_IN, PTX3_OUT, PTX3_IN_PU),
+       PINMUX_DATA(PTX2_DATA, PTX2_IN, PTX2_OUT, PTX2_IN_PU),
+       PINMUX_DATA(PTX1_DATA, PTX1_IN, PTX1_OUT, PTX1_IN_PU),
+       PINMUX_DATA(PTX0_DATA, PTX0_IN, PTX0_OUT, PTX0_IN_PU),
+
+       /* PTY GPIO */
+       PINMUX_DATA(PTY7_DATA, PTY7_IN, PTY7_OUT, PTY7_IN_PU),
+       PINMUX_DATA(PTY6_DATA, PTY6_IN, PTY6_OUT, PTY6_IN_PU),
+       PINMUX_DATA(PTY5_DATA, PTY5_IN, PTY5_OUT, PTY5_IN_PU),
+       PINMUX_DATA(PTY4_DATA, PTY4_IN, PTY4_OUT, PTY4_IN_PU),
+       PINMUX_DATA(PTY3_DATA, PTY3_IN, PTY3_OUT, PTY3_IN_PU),
+       PINMUX_DATA(PTY2_DATA, PTY2_IN, PTY2_OUT, PTY2_IN_PU),
+       PINMUX_DATA(PTY1_DATA, PTY1_IN, PTY1_OUT, PTY1_IN_PU),
+       PINMUX_DATA(PTY0_DATA, PTY0_IN, PTY0_OUT, PTY0_IN_PU),
+
+       /* PTZ GPIO */
+       PINMUX_DATA(PTZ7_DATA, PTZ7_IN, PTZ7_OUT, PTZ7_IN_PU),
+       PINMUX_DATA(PTZ6_DATA, PTZ6_IN, PTZ6_OUT, PTZ6_IN_PU),
+       PINMUX_DATA(PTZ5_DATA, PTZ5_IN, PTZ5_OUT, PTZ5_IN_PU),
+       PINMUX_DATA(PTZ4_DATA, PTZ4_IN, PTZ4_OUT, PTZ4_IN_PU),
+       PINMUX_DATA(PTZ3_DATA, PTZ3_IN, PTZ3_OUT, PTZ3_IN_PU),
+       PINMUX_DATA(PTZ2_DATA, PTZ2_IN, PTZ2_OUT, PTZ2_IN_PU),
+       PINMUX_DATA(PTZ1_DATA, PTZ1_IN, PTZ1_OUT, PTZ1_IN_PU),
+       PINMUX_DATA(PTZ0_DATA, PTZ0_IN, PTZ0_OUT, PTZ0_IN_PU),
+
+       /* PTA FN */
+       PINMUX_DATA(D23_MARK,   PSA15_0, PSA14_0, PTA7_FN),
+       PINMUX_DATA(D22_MARK,   PSA15_0, PSA14_0, PTA6_FN),
+       PINMUX_DATA(D21_MARK,   PSA15_0, PSA14_0, PTA5_FN),
+       PINMUX_DATA(D20_MARK,   PSA15_0, PSA14_0, PTA4_FN),
+       PINMUX_DATA(D19_MARK,   PSA15_0, PSA14_0, PTA3_FN),
+       PINMUX_DATA(D18_MARK,   PSA15_0, PSA14_0, PTA2_FN),
+       PINMUX_DATA(D17_MARK,   PSA15_0, PSA14_0, PTA1_FN),
+       PINMUX_DATA(D16_MARK,   PSA15_0, PSA14_0, PTA0_FN),
+
+       PINMUX_DATA(KEYOUT2_MARK,       PSA15_0, PSA14_1, PTA7_FN),
+       PINMUX_DATA(KEYOUT1_MARK,       PSA15_0, PSA14_1, PTA6_FN),
+       PINMUX_DATA(KEYOUT0_MARK,       PSA15_0, PSA14_1, PTA5_FN),
+       PINMUX_DATA(KEYIN4_MARK,        PSA15_0, PSA14_1, PTA4_FN),
+       PINMUX_DATA(KEYIN3_MARK,        PSA15_0, PSA14_1, PTA3_FN),
+       PINMUX_DATA(KEYIN2_MARK,        PSA15_0, PSA14_1, PTA2_FN),
+       PINMUX_DATA(KEYIN1_MARK,        PSA15_0, PSA14_1, PTA1_FN),
+       PINMUX_DATA(KEYIN0_MARK,        PSA15_0, PSA14_1, PTA0_FN),
+
+       PINMUX_DATA(IDED15_MARK,        PSA15_1, PSA14_0, PTA7_FN),
+       PINMUX_DATA(IDED14_MARK,        PSA15_1, PSA14_0, PTA6_FN),
+       PINMUX_DATA(IDED13_MARK,        PSA15_1, PSA14_0, PTA5_FN),
+       PINMUX_DATA(IDED12_MARK,        PSA15_1, PSA14_0, PTA4_FN),
+       PINMUX_DATA(IDED11_MARK,        PSA15_1, PSA14_0, PTA3_FN),
+       PINMUX_DATA(IDED10_MARK,        PSA15_1, PSA14_0, PTA2_FN),
+       PINMUX_DATA(IDED9_MARK,         PSA15_1, PSA14_0, PTA1_FN),
+       PINMUX_DATA(IDED8_MARK,         PSA15_1, PSA14_0, PTA0_FN),
+
+       /* PTB FN */
+       PINMUX_DATA(D31_MARK,           PSE15_0, PSE14_0, PTB7_FN),
+       PINMUX_DATA(D30_MARK,           PSE15_0, PSE14_0, PTB6_FN),
+       PINMUX_DATA(D29_MARK,           PSE11_0,          PTB5_FN),
+       PINMUX_DATA(D28_MARK,           PSE11_0,          PTB4_FN),
+       PINMUX_DATA(D27_MARK,           PSE11_0,          PTB3_FN),
+       PINMUX_DATA(D26_MARK,           PSA15_0, PSA14_0, PTB2_FN),
+       PINMUX_DATA(D25_MARK,           PSA15_0, PSA14_0, PTB1_FN),
+       PINMUX_DATA(D24_MARK,           PSA15_0, PSA14_0, PTB0_FN),
+
+       PINMUX_DATA(IDEA1_MARK,         PSE15_1, PSE14_0, PTB7_FN),
+       PINMUX_DATA(IDEA0_MARK,         PSE15_1, PSE14_0, PTB6_FN),
+       PINMUX_DATA(IODREQ_MARK,        PSE11_1,          PTB5_FN),
+       PINMUX_DATA(IDECS0_MARK,        PSE11_1,          PTB4_FN),
+       PINMUX_DATA(IDECS1_MARK,        PSE11_1,          PTB3_FN),
+       PINMUX_DATA(IDEIORD_MARK,       PSA15_1, PSA14_0, PTB2_FN),
+       PINMUX_DATA(IDEIOWR_MARK,       PSA15_1, PSA14_0, PTB1_FN),
+       PINMUX_DATA(IDEINT_MARK,        PSA15_1, PSA14_0, PTB0_FN),
+
+       PINMUX_DATA(TPUTO1_MARK,        PSE15_0, PSE14_1, PTB7_FN),
+       PINMUX_DATA(TPUTO0_MARK,        PSE15_0, PSE14_1, PTB6_FN),
+
+       PINMUX_DATA(KEYOUT5_IN5_MARK,   PSA15_0, PSA14_1, PTB2_FN),
+       PINMUX_DATA(KEYOUT4_IN6_MARK,   PSA15_0, PSA14_1, PTB1_FN),
+       PINMUX_DATA(KEYOUT3_MARK,       PSA15_0, PSA14_1, PTB0_FN),
+
+       /* PTC FN */
+       PINMUX_DATA(LCDD7_MARK, PSD5_0, PTC7_FN),
+       PINMUX_DATA(LCDD6_MARK, PSD5_0, PTC6_FN),
+       PINMUX_DATA(LCDD5_MARK, PSD5_0, PTC5_FN),
+       PINMUX_DATA(LCDD4_MARK, PSD5_0, PTC4_FN),
+       PINMUX_DATA(LCDD3_MARK, PSD5_0, PTC3_FN),
+       PINMUX_DATA(LCDD2_MARK, PSD5_0, PTC2_FN),
+       PINMUX_DATA(LCDD1_MARK, PSD5_0, PTC1_FN),
+       PINMUX_DATA(LCDD0_MARK, PSD5_0, PTC0_FN),
+
+       /* PTD FN */
+       PINMUX_DATA(LCDD15_MARK, PSD5_0, PTD7_FN),
+       PINMUX_DATA(LCDD14_MARK, PSD5_0, PTD6_FN),
+       PINMUX_DATA(LCDD13_MARK, PSD5_0, PTD5_FN),
+       PINMUX_DATA(LCDD12_MARK, PSD5_0, PTD4_FN),
+       PINMUX_DATA(LCDD11_MARK, PSD5_0, PTD3_FN),
+       PINMUX_DATA(LCDD10_MARK, PSD5_0, PTD2_FN),
+       PINMUX_DATA(LCDD9_MARK,  PSD5_0, PTD1_FN),
+       PINMUX_DATA(LCDD8_MARK,  PSD5_0, PTD0_FN),
+
+       /* PTE FN */
+       PINMUX_DATA(FSIMCKB_MARK, PTE7_FN),
+       PINMUX_DATA(FSIMCKA_MARK, PTE6_FN),
+
+       PINMUX_DATA(LCDD21_MARK,        PSC5_0, PSC4_0, PTE5_FN),
+       PINMUX_DATA(LCDD20_MARK,        PSD3_0, PSD2_0, PTE4_FN),
+       PINMUX_DATA(LCDD19_MARK,        PSA3_0, PSA2_0, PTE3_FN),
+       PINMUX_DATA(LCDD18_MARK,        PSA3_0, PSA2_0, PTE2_FN),
+       PINMUX_DATA(LCDD17_MARK,        PSD5_0,         PTE1_FN),
+       PINMUX_DATA(LCDD16_MARK,        PSD5_0,         PTE0_FN),
+
+       PINMUX_DATA(SCIF2_L_TXD_MARK,   PSC5_0, PSC4_1, PTE5_FN),
+       PINMUX_DATA(SCIF4_SCK_MARK,     PSD3_0, PSD2_1, PTE4_FN),
+       PINMUX_DATA(SCIF4_RXD_MARK,     PSA3_0, PSA2_1, PTE3_FN),
+       PINMUX_DATA(SCIF4_TXD_MARK,     PSA3_0, PSA2_1, PTE2_FN),
+
+       /* PTF FN */
+       PINMUX_DATA(LCDVSYN_MARK,       PSD8_0,          PTF7_FN),
+       PINMUX_DATA(LCDDISP_MARK,       PSD10_0, PSD9_0, PTF6_FN),
+       PINMUX_DATA(LCDHSYN_MARK,       PSD10_0, PSD9_0, PTF5_FN),
+       PINMUX_DATA(LCDDON_MARK,        PSD8_0,          PTF4_FN),
+       PINMUX_DATA(LCDDCK_MARK,        PSD10_0, PSD9_0, PTF3_FN),
+       PINMUX_DATA(LCDVEPWC_MARK,      PSA6_0,          PTF2_FN),
+       PINMUX_DATA(LCDD23_MARK,        PSC7_0,  PSC6_0, PTF1_FN),
+       PINMUX_DATA(LCDD22_MARK,        PSC5_0,  PSC4_0, PTF0_FN),
+
+       PINMUX_DATA(LCDRS_MARK,         PSD10_0, PSD9_1, PTF6_FN),
+       PINMUX_DATA(LCDCS_MARK,         PSD10_0, PSD9_1, PTF5_FN),
+       PINMUX_DATA(LCDWR_MARK,         PSD10_0, PSD9_1, PTF3_FN),
+
+       PINMUX_DATA(SCIF0_TXD_MARK,     PSA6_1,          PTF2_FN),
+       PINMUX_DATA(SCIF2_L_SCK_MARK,   PSC7_0,  PSC6_1, PTF1_FN),
+       PINMUX_DATA(SCIF2_L_RXD_MARK,   PSC5_0,  PSC4_1, PTF0_FN),
+
+       /* PTG FN */
+       PINMUX_DATA(AUDCK_MARK,   PTG5_FN),
+       PINMUX_DATA(AUDSYNC_MARK, PTG4_FN),
+       PINMUX_DATA(AUDATA3_MARK, PTG3_FN),
+       PINMUX_DATA(AUDATA2_MARK, PTG2_FN),
+       PINMUX_DATA(AUDATA1_MARK, PTG1_FN),
+       PINMUX_DATA(AUDATA0_MARK, PTG0_FN),
+
+       /* PTH FN */
+       PINMUX_DATA(VIO0_VD_MARK,  PTH7_FN),
+       PINMUX_DATA(VIO0_CLK_MARK, PTH6_FN),
+       PINMUX_DATA(VIO0_D7_MARK,  PTH5_FN),
+       PINMUX_DATA(VIO0_D6_MARK,  PTH4_FN),
+       PINMUX_DATA(VIO0_D5_MARK,  PTH3_FN),
+       PINMUX_DATA(VIO0_D4_MARK,  PTH2_FN),
+       PINMUX_DATA(VIO0_D3_MARK,  PTH1_FN),
+       PINMUX_DATA(VIO0_D2_MARK,  PTH0_FN),
+
+       /* PTJ FN */
+       PINMUX_DATA(PDSTATUS_MARK,      PTJ7_FN),
+       PINMUX_DATA(STATUS2_MARK,       PTJ6_FN),
+       PINMUX_DATA(STATUS0_MARK,       PTJ5_FN),
+       PINMUX_DATA(A25_MARK,           PSA8_0, PTJ3_FN),
+       PINMUX_DATA(BS_MARK,            PSA8_1, PTJ3_FN),
+       PINMUX_DATA(A24_MARK,           PTJ2_FN),
+       PINMUX_DATA(A23_MARK,           PTJ1_FN),
+       PINMUX_DATA(A22_MARK,           PTJ0_FN),
+
+       /* PTK FN */
+       PINMUX_DATA(VIO1_D5_MARK,       PSB7_0, PSB6_0, PTK7_FN),
+       PINMUX_DATA(VIO1_D4_MARK,       PSB7_0, PSB6_0, PTK6_FN),
+       PINMUX_DATA(VIO1_D3_MARK,       PSB7_0, PSB6_0, PTK5_FN),
+       PINMUX_DATA(VIO1_D2_MARK,       PSB7_0, PSB6_0, PTK4_FN),
+       PINMUX_DATA(VIO1_D1_MARK,       PSB7_0, PSB6_0, PTK3_FN),
+       PINMUX_DATA(VIO1_D0_MARK,       PSB7_0, PSB6_0, PTK2_FN),
+
+       PINMUX_DATA(VIO0_D13_MARK,      PSB7_0, PSB6_1, PTK7_FN),
+       PINMUX_DATA(VIO0_D12_MARK,      PSB7_0, PSB6_1, PTK6_FN),
+       PINMUX_DATA(VIO0_D11_MARK,      PSB7_0, PSB6_1, PTK5_FN),
+       PINMUX_DATA(VIO0_D10_MARK,      PSB7_0, PSB6_1, PTK4_FN),
+       PINMUX_DATA(VIO0_D9_MARK,       PSB7_0, PSB6_1, PTK3_FN),
+       PINMUX_DATA(VIO0_D8_MARK,       PSB7_0, PSB6_1, PTK2_FN),
+
+       PINMUX_DATA(IDED5_MARK,         PSB7_1, PSB6_0, PTK7_FN),
+       PINMUX_DATA(IDED4_MARK,         PSB7_1, PSB6_0, PTK6_FN),
+       PINMUX_DATA(IDED3_MARK,         PSB7_1, PSB6_0, PTK5_FN),
+       PINMUX_DATA(IDED2_MARK,         PSB7_1, PSB6_0, PTK4_FN),
+       PINMUX_DATA(IDED1_MARK,         PSB7_1, PSB6_0, PTK3_FN),
+       PINMUX_DATA(IDED0_MARK,         PSB7_1, PSB6_0, PTK2_FN),
+
+       PINMUX_DATA(VIO0_FLD_MARK,      PTK1_FN),
+       PINMUX_DATA(VIO0_HD_MARK,       PTK0_FN),
+
+       /* PTL FN */
+       PINMUX_DATA(DV_D5_MARK,         PSB9_0, PSB8_0, PTL7_FN),
+       PINMUX_DATA(DV_D4_MARK,         PSB9_0, PSB8_0, PTL6_FN),
+       PINMUX_DATA(DV_D3_MARK,         PSE7_0, PSE6_0, PTL5_FN),
+       PINMUX_DATA(DV_D2_MARK,         PSC9_0, PSC8_0, PTL4_FN),
+       PINMUX_DATA(DV_D1_MARK,         PSC9_0, PSC8_0, PTL3_FN),
+       PINMUX_DATA(DV_D0_MARK,         PSC9_0, PSC8_0, PTL2_FN),
+       PINMUX_DATA(DV_D15_MARK,        PSD4_0,         PTL1_FN),
+       PINMUX_DATA(DV_D14_MARK,        PSE5_0, PSE4_0, PTL0_FN),
+
+       PINMUX_DATA(SCIF3_V_SCK_MARK,   PSB9_0, PSB8_1, PTL7_FN),
+       PINMUX_DATA(SCIF3_V_RXD_MARK,   PSB9_0, PSB8_1, PTL6_FN),
+       PINMUX_DATA(SCIF3_V_TXD_MARK,   PSE7_0, PSE6_1, PTL5_FN),
+       PINMUX_DATA(SCIF1_SCK_MARK,     PSC9_0, PSC8_1, PTL4_FN),
+       PINMUX_DATA(SCIF1_RXD_MARK,     PSC9_0, PSC8_1, PTL3_FN),
+       PINMUX_DATA(SCIF1_TXD_MARK,     PSC9_0, PSC8_1, PTL2_FN),
+
+       PINMUX_DATA(RMII_RXD0_MARK,     PSB9_1, PSB8_0, PTL7_FN),
+       PINMUX_DATA(RMII_RXD1_MARK,     PSB9_1, PSB8_0, PTL6_FN),
+       PINMUX_DATA(RMII_REF_CLK_MARK,  PSE7_1, PSE6_0, PTL5_FN),
+       PINMUX_DATA(RMII_TX_EN_MARK,    PSC9_1, PSC8_0, PTL4_FN),
+       PINMUX_DATA(RMII_TXD0_MARK,     PSC9_1, PSC8_0, PTL3_FN),
+       PINMUX_DATA(RMII_TXD1_MARK,     PSC9_1, PSC8_0, PTL2_FN),
+
+       PINMUX_DATA(MSIOF0_MCK_MARK,    PSE5_0, PSE4_1, PTL0_FN),
+
+       /* PTM FN */
+       PINMUX_DATA(DV_D13_MARK,        PSC13_0, PSC12_0, PTM7_FN),
+       PINMUX_DATA(DV_D12_MARK,        PSC13_0, PSC12_0, PTM6_FN),
+       PINMUX_DATA(DV_D11_MARK,        PSC13_0, PSC12_0, PTM5_FN),
+       PINMUX_DATA(DV_D10_MARK,        PSC13_0, PSC12_0, PTM4_FN),
+       PINMUX_DATA(DV_D9_MARK,         PSC11_0, PSC10_0, PTM3_FN),
+       PINMUX_DATA(DV_D8_MARK,         PSC11_0, PSC10_0, PTM2_FN),
+
+       PINMUX_DATA(MSIOF0_TSCK_MARK,   PSC13_0, PSC12_1, PTM7_FN),
+       PINMUX_DATA(MSIOF0_RXD_MARK,    PSC13_0, PSC12_1, PTM6_FN),
+       PINMUX_DATA(MSIOF0_TXD_MARK,    PSC13_0, PSC12_1, PTM5_FN),
+       PINMUX_DATA(MSIOF0_TSYNC_MARK,  PSC13_0, PSC12_1, PTM4_FN),
+       PINMUX_DATA(MSIOF0_SS1_MARK,    PSC11_0, PSC10_1, PTM3_FN),
+       PINMUX_DATA(MSIOF0_RSCK_MARK,   PSC11_1, PSC10_0, PTM3_FN),
+       PINMUX_DATA(MSIOF0_SS2_MARK,    PSC11_0, PSC10_1, PTM2_FN),
+       PINMUX_DATA(MSIOF0_RSYNC_MARK,  PSC11_1, PSC10_0, PTM2_FN),
+
+       PINMUX_DATA(LCDVCPWC_MARK,      PSA6_0, PTM1_FN),
+       PINMUX_DATA(LCDRD_MARK,         PSA7_0, PTM0_FN),
+
+       PINMUX_DATA(SCIF0_RXD_MARK,     PSA6_1, PTM1_FN),
+       PINMUX_DATA(SCIF0_SCK_MARK,     PSA7_1, PTM0_FN),
+
+       /* PTN FN */
+       PINMUX_DATA(VIO0_D1_MARK,       PTN7_FN),
+       PINMUX_DATA(VIO0_D0_MARK,       PTN6_FN),
+
+       PINMUX_DATA(DV_CLKI_MARK,       PSD11_0,          PTN5_FN),
+       PINMUX_DATA(DV_CLK_MARK,        PSD13_0, PSD12_0, PTN4_FN),
+       PINMUX_DATA(DV_VSYNC_MARK,      PSD15_0, PSD14_0, PTN3_FN),
+       PINMUX_DATA(DV_HSYNC_MARK,      PSB5_0,  PSB4_0,  PTN2_FN),
+       PINMUX_DATA(DV_D7_MARK,         PSB3_0,  PSB2_0,  PTN1_FN),
+       PINMUX_DATA(DV_D6_MARK,         PSB1_0,  PSB0_0,  PTN0_FN),
+
+       PINMUX_DATA(SCIF2_V_SCK_MARK,   PSD13_0, PSD12_1, PTN4_FN),
+       PINMUX_DATA(SCIF2_V_RXD_MARK,   PSD15_0, PSD14_1, PTN3_FN),
+       PINMUX_DATA(SCIF2_V_TXD_MARK,   PSB5_0,  PSB4_1,  PTN2_FN),
+       PINMUX_DATA(SCIF3_V_CTS_MARK,   PSB3_0,  PSB2_1,  PTN1_FN),
+       PINMUX_DATA(SCIF3_V_RTS_MARK,   PSB1_0,  PSB0_1,  PTN0_FN),
+
+       PINMUX_DATA(RMII_RX_ER_MARK,    PSB3_1, PSB2_0, PTN1_FN),
+       PINMUX_DATA(RMII_CRS_DV_MARK,   PSB1_1, PSB0_0, PTN0_FN),
+
+       /* PTQ FN */
+       PINMUX_DATA(D7_MARK, PTQ7_FN),
+       PINMUX_DATA(D6_MARK, PTQ6_FN),
+       PINMUX_DATA(D5_MARK, PTQ5_FN),
+       PINMUX_DATA(D4_MARK, PTQ4_FN),
+       PINMUX_DATA(D3_MARK, PTQ3_FN),
+       PINMUX_DATA(D2_MARK, PTQ2_FN),
+       PINMUX_DATA(D1_MARK, PTQ1_FN),
+       PINMUX_DATA(D0_MARK, PTQ0_FN),
+
+       /* PTR FN */
+       PINMUX_DATA(CS6B_CE1B_MARK,                     PTR7_FN),
+       PINMUX_DATA(CS6A_CE2B_MARK,                     PTR6_FN),
+       PINMUX_DATA(CS5B_CE1A_MARK,                     PTR5_FN),
+       PINMUX_DATA(CS5A_CE2A_MARK,                     PTR4_FN),
+       PINMUX_DATA(IOIS16_MARK,        PSA5_0,         PTR3_FN),
+       PINMUX_DATA(WAIT_MARK,                          PTR2_FN),
+       PINMUX_DATA(WE3_ICIOWR_MARK,    PSA1_0, PSA0_0, PTR1_FN),
+       PINMUX_DATA(WE2_ICIORD_MARK,    PSD1_0, PSD0_0, PTR0_FN),
+
+       PINMUX_DATA(LCDLCLK_MARK,       PSA5_1,         PTR3_FN),
+
+       PINMUX_DATA(IDEA2_MARK,         PSD1_1, PSD0_0, PTR0_FN),
+
+       PINMUX_DATA(TPUTO3_MARK,        PSA1_0, PSA0_1, PTR1_FN),
+       PINMUX_DATA(TPUTI3_MARK,        PSA1_1, PSA0_0, PTR1_FN),
+       PINMUX_DATA(TPUTO2_MARK,        PSD1_0, PSD0_1, PTR0_FN),
+
+       /* PTS FN */
+       PINMUX_DATA(VIO_CKO_MARK,       PTS6_FN),
+
+       PINMUX_DATA(TPUTI2_MARK,        PSE9_0, PSE8_1, PTS5_FN),
+
+       PINMUX_DATA(IDEIORDY_MARK,      PSE9_1, PSE8_0, PTS5_FN),
+
+       PINMUX_DATA(VIO1_FLD_MARK,      PSE9_0, PSE8_0, PTS5_FN),
+       PINMUX_DATA(VIO1_HD_MARK,       PSA10_0,        PTS4_FN),
+       PINMUX_DATA(VIO1_VD_MARK,       PSA9_0,         PTS3_FN),
+       PINMUX_DATA(VIO1_CLK_MARK,      PSA9_0,         PTS2_FN),
+       PINMUX_DATA(VIO1_D7_MARK,       PSB7_0, PSB6_0, PTS1_FN),
+       PINMUX_DATA(VIO1_D6_MARK,       PSB7_0, PSB6_0, PTS0_FN),
+
+       PINMUX_DATA(SCIF5_SCK_MARK,     PSA10_1, PTS4_FN),
+       PINMUX_DATA(SCIF5_RXD_MARK,     PSA9_1,  PTS3_FN),
+       PINMUX_DATA(SCIF5_TXD_MARK,     PSA9_1,  PTS2_FN),
+
+       PINMUX_DATA(VIO0_D15_MARK,      PSB7_0, PSB6_1, PTS1_FN),
+       PINMUX_DATA(VIO0_D14_MARK,      PSB7_0, PSB6_1, PTS0_FN),
+
+       PINMUX_DATA(IDED7_MARK,         PSB7_1, PSB6_0, PTS1_FN),
+       PINMUX_DATA(IDED6_MARK,         PSB7_1, PSB6_0, PTS0_FN),
+
+       /* PTT FN */
+       PINMUX_DATA(D15_MARK, PTT7_FN),
+       PINMUX_DATA(D14_MARK, PTT6_FN),
+       PINMUX_DATA(D13_MARK, PTT5_FN),
+       PINMUX_DATA(D12_MARK, PTT4_FN),
+       PINMUX_DATA(D11_MARK, PTT3_FN),
+       PINMUX_DATA(D10_MARK, PTT2_FN),
+       PINMUX_DATA(D9_MARK,  PTT1_FN),
+       PINMUX_DATA(D8_MARK,  PTT0_FN),
+
+       /* PTU FN */
+       PINMUX_DATA(DMAC_DACK0_MARK, PTU7_FN),
+       PINMUX_DATA(DMAC_DREQ0_MARK, PTU6_FN),
+
+       PINMUX_DATA(FSIOASD_MARK,       PSE1_0, PTU5_FN),
+       PINMUX_DATA(FSIIABCK_MARK,      PSE1_0, PTU4_FN),
+       PINMUX_DATA(FSIIALRCK_MARK,     PSE1_0, PTU3_FN),
+       PINMUX_DATA(FSIOABCK_MARK,      PSE1_0, PTU2_FN),
+       PINMUX_DATA(FSIOALRCK_MARK,     PSE1_0, PTU1_FN),
+       PINMUX_DATA(CLKAUDIOAO_MARK,    PSE0_0, PTU0_FN),
+
+       /* PTV FN */
+       PINMUX_DATA(FSIIBSD_MARK,       PSD7_0,  PSD6_0,  PTV7_FN),
+       PINMUX_DATA(FSIOBSD_MARK,       PSD7_0,  PSD6_0,  PTV6_FN),
+       PINMUX_DATA(FSIIBBCK_MARK,      PSC15_0, PSC14_0, PTV5_FN),
+       PINMUX_DATA(FSIIBLRCK_MARK,     PSC15_0, PSC14_0, PTV4_FN),
+       PINMUX_DATA(FSIOBBCK_MARK,      PSC15_0, PSC14_0, PTV3_FN),
+       PINMUX_DATA(FSIOBLRCK_MARK,     PSC15_0, PSC14_0, PTV2_FN),
+       PINMUX_DATA(CLKAUDIOBO_MARK,    PSE3_0,  PSE2_0,  PTV1_FN),
+       PINMUX_DATA(FSIIASD_MARK,       PSE10_0,          PTV0_FN),
+
+       PINMUX_DATA(MSIOF1_SS2_MARK,    PSD7_0,  PSD6_1,  PTV7_FN),
+       PINMUX_DATA(MSIOF1_RSYNC_MARK,  PSD7_1,  PSD6_0,  PTV7_FN),
+       PINMUX_DATA(MSIOF1_SS1_MARK,    PSD7_0,  PSD6_1,  PTV6_FN),
+       PINMUX_DATA(MSIOF1_RSCK_MARK,   PSD7_1,  PSD6_0,  PTV6_FN),
+       PINMUX_DATA(MSIOF1_RXD_MARK,    PSC15_0, PSC14_1, PTV5_FN),
+       PINMUX_DATA(MSIOF1_TSYNC_MARK,  PSC15_0, PSC14_1, PTV4_FN),
+       PINMUX_DATA(MSIOF1_TSCK_MARK,   PSC15_0, PSC14_1, PTV3_FN),
+       PINMUX_DATA(MSIOF1_TXD_MARK,    PSC15_0, PSC14_1, PTV2_FN),
+       PINMUX_DATA(MSIOF1_MCK_MARK,    PSE3_0,  PSE2_1,  PTV1_FN),
+
+       /* PTW FN */
+       PINMUX_DATA(MMC_D7_MARK,        PSE13_0, PSE12_0, PTW7_FN),
+       PINMUX_DATA(MMC_D6_MARK,        PSE13_0, PSE12_0, PTW6_FN),
+       PINMUX_DATA(MMC_D5_MARK,        PSE13_0, PSE12_0, PTW5_FN),
+       PINMUX_DATA(MMC_D4_MARK,        PSE13_0, PSE12_0, PTW4_FN),
+       PINMUX_DATA(MMC_D3_MARK,        PSA13_0,          PTW3_FN),
+       PINMUX_DATA(MMC_D2_MARK,        PSA13_0,          PTW2_FN),
+       PINMUX_DATA(MMC_D1_MARK,        PSA13_0,          PTW1_FN),
+       PINMUX_DATA(MMC_D0_MARK,        PSA13_0,          PTW0_FN),
+
+       PINMUX_DATA(SDHI1CD_MARK,       PSE13_0, PSE12_1, PTW7_FN),
+       PINMUX_DATA(SDHI1WP_MARK,       PSE13_0, PSE12_1, PTW6_FN),
+       PINMUX_DATA(SDHI1D3_MARK,       PSE13_0, PSE12_1, PTW5_FN),
+       PINMUX_DATA(SDHI1D2_MARK,       PSE13_0, PSE12_1, PTW4_FN),
+       PINMUX_DATA(SDHI1D1_MARK,       PSA13_1,          PTW3_FN),
+       PINMUX_DATA(SDHI1D0_MARK,       PSA13_1,          PTW2_FN),
+       PINMUX_DATA(SDHI1CMD_MARK,      PSA13_1,          PTW1_FN),
+       PINMUX_DATA(SDHI1CLK_MARK,      PSA13_1,          PTW0_FN),
+
+       PINMUX_DATA(IODACK_MARK,        PSE13_1, PSE12_0, PTW7_FN),
+       PINMUX_DATA(IDERST_MARK,        PSE13_1, PSE12_0, PTW6_FN),
+       PINMUX_DATA(EXBUF_ENB_MARK,     PSE13_1, PSE12_0, PTW5_FN),
+       PINMUX_DATA(DIRECTION_MARK,     PSE13_1, PSE12_0, PTW4_FN),
+
+       /* PTX FN */
+       PINMUX_DATA(DMAC_DACK1_MARK,    PSA12_0, PTX7_FN),
+       PINMUX_DATA(DMAC_DREQ1_MARK,    PSA12_0, PTX6_FN),
+
+       PINMUX_DATA(IRDA_OUT_MARK,      PSA12_1, PTX7_FN),
+       PINMUX_DATA(IRDA_IN_MARK,       PSA12_1, PTX6_FN),
+
+       PINMUX_DATA(TSIF_TS0_SDAT_MARK, PSC0_0, PTX5_FN),
+       PINMUX_DATA(TSIF_TS0_SCK_MARK,  PSC1_0, PTX4_FN),
+       PINMUX_DATA(TSIF_TS0_SDEN_MARK, PSC2_0, PTX3_FN),
+       PINMUX_DATA(TSIF_TS0_SPSYNC_MARK,       PTX2_FN),
+
+       PINMUX_DATA(LNKSTA_MARK,        PSC0_1, PTX5_FN),
+       PINMUX_DATA(MDIO_MARK,          PSC1_1, PTX4_FN),
+       PINMUX_DATA(MDC_MARK,           PSC2_1, PTX3_FN),
+
+       PINMUX_DATA(MMC_CLK_MARK, PTX1_FN),
+       PINMUX_DATA(MMC_CMD_MARK, PTX0_FN),
+
+       /* PTY FN */
+       PINMUX_DATA(SDHI0CD_MARK,  PTY7_FN),
+       PINMUX_DATA(SDHI0WP_MARK,  PTY6_FN),
+       PINMUX_DATA(SDHI0D3_MARK,  PTY5_FN),
+       PINMUX_DATA(SDHI0D2_MARK,  PTY4_FN),
+       PINMUX_DATA(SDHI0D1_MARK,  PTY3_FN),
+       PINMUX_DATA(SDHI0D0_MARK,  PTY2_FN),
+       PINMUX_DATA(SDHI0CMD_MARK, PTY1_FN),
+       PINMUX_DATA(SDHI0CLK_MARK, PTY0_FN),
+
+       /* PTZ FN */
+       PINMUX_DATA(INTC_IRQ7_MARK,     PSB10_0, PTZ7_FN),
+       PINMUX_DATA(INTC_IRQ6_MARK,     PSB11_0, PTZ6_FN),
+       PINMUX_DATA(INTC_IRQ5_MARK,     PSB12_0, PTZ5_FN),
+       PINMUX_DATA(INTC_IRQ4_MARK,     PSB13_0, PTZ4_FN),
+       PINMUX_DATA(INTC_IRQ3_MARK,     PSB14_0, PTZ3_FN),
+       PINMUX_DATA(INTC_IRQ2_MARK,              PTZ2_FN),
+       PINMUX_DATA(INTC_IRQ1_MARK,              PTZ1_FN),
+       PINMUX_DATA(INTC_IRQ0_MARK,              PTZ0_FN),
+
+       PINMUX_DATA(SCIF3_I_CTS_MARK,   PSB10_1, PTZ7_FN),
+       PINMUX_DATA(SCIF3_I_RTS_MARK,   PSB11_1, PTZ6_FN),
+       PINMUX_DATA(SCIF3_I_SCK_MARK,   PSB12_1, PTZ5_FN),
+       PINMUX_DATA(SCIF3_I_RXD_MARK,   PSB13_1, PTZ4_FN),
+       PINMUX_DATA(SCIF3_I_TXD_MARK,   PSB14_1, PTZ3_FN),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+       /* PTA */
+       PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
+       PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
+       PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
+       PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
+       PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
+       PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
+       PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
+       PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
+
+       /* PTB */
+       PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
+       PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
+       PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
+       PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
+       PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
+       PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
+       PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
+       PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
+
+       /* PTC */
+       PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
+       PINMUX_GPIO(GPIO_PTC6, PTC6_DATA),
+       PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
+       PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
+       PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
+       PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
+       PINMUX_GPIO(GPIO_PTC1, PTC1_DATA),
+       PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
+
+       /* PTD */
+       PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
+       PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
+       PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
+       PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
+       PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
+       PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
+       PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
+       PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
+
+       /* PTE */
+       PINMUX_GPIO(GPIO_PTE7, PTE7_DATA),
+       PINMUX_GPIO(GPIO_PTE6, PTE6_DATA),
+       PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
+       PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
+       PINMUX_GPIO(GPIO_PTE3, PTE3_DATA),
+       PINMUX_GPIO(GPIO_PTE2, PTE2_DATA),
+       PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
+       PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
+
+       /* PTF */
+       PINMUX_GPIO(GPIO_PTF7, PTF7_DATA),
+       PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
+       PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
+       PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
+       PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
+       PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
+       PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
+       PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
+
+       /* PTG */
+       PINMUX_GPIO(GPIO_PTG5, PTG5_DATA),
+       PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
+       PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
+       PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
+       PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
+       PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
+
+       /* PTH */
+       PINMUX_GPIO(GPIO_PTH7, PTH7_DATA),
+       PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
+       PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
+       PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
+       PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
+       PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
+       PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
+       PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
+
+       /* PTJ */
+       PINMUX_GPIO(GPIO_PTJ7, PTJ7_DATA),
+       PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
+       PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
+       PINMUX_GPIO(GPIO_PTJ3, PTJ3_DATA),
+       PINMUX_GPIO(GPIO_PTJ2, PTJ2_DATA),
+       PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
+       PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
+
+       /* PTK */
+       PINMUX_GPIO(GPIO_PTK7, PTK7_DATA),
+       PINMUX_GPIO(GPIO_PTK6, PTK6_DATA),
+       PINMUX_GPIO(GPIO_PTK5, PTK5_DATA),
+       PINMUX_GPIO(GPIO_PTK4, PTK4_DATA),
+       PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
+       PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
+       PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
+       PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
+
+       /* PTL */
+       PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
+       PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
+       PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
+       PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
+       PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
+       PINMUX_GPIO(GPIO_PTL2, PTL2_DATA),
+       PINMUX_GPIO(GPIO_PTL1, PTL1_DATA),
+       PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
+
+       /* PTM */
+       PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
+       PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
+       PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
+       PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
+       PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
+       PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
+       PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
+       PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
+
+       /* PTN */
+       PINMUX_GPIO(GPIO_PTN7, PTN7_DATA),
+       PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
+       PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
+       PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
+       PINMUX_GPIO(GPIO_PTN3, PTN3_DATA),
+       PINMUX_GPIO(GPIO_PTN2, PTN2_DATA),
+       PINMUX_GPIO(GPIO_PTN1, PTN1_DATA),
+       PINMUX_GPIO(GPIO_PTN0, PTN0_DATA),
+
+       /* PTQ */
+       PINMUX_GPIO(GPIO_PTQ7, PTQ7_DATA),
+       PINMUX_GPIO(GPIO_PTQ6, PTQ6_DATA),
+       PINMUX_GPIO(GPIO_PTQ5, PTQ5_DATA),
+       PINMUX_GPIO(GPIO_PTQ4, PTQ4_DATA),
+       PINMUX_GPIO(GPIO_PTQ3, PTQ3_DATA),
+       PINMUX_GPIO(GPIO_PTQ2, PTQ2_DATA),
+       PINMUX_GPIO(GPIO_PTQ1, PTQ1_DATA),
+       PINMUX_GPIO(GPIO_PTQ0, PTQ0_DATA),
+
+       /* PTR */
+       PINMUX_GPIO(GPIO_PTR7, PTR7_DATA),
+       PINMUX_GPIO(GPIO_PTR6, PTR6_DATA),
+       PINMUX_GPIO(GPIO_PTR5, PTR5_DATA),
+       PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
+       PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
+       PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
+       PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
+       PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
+
+       /* PTS */
+       PINMUX_GPIO(GPIO_PTS6, PTS6_DATA),
+       PINMUX_GPIO(GPIO_PTS5, PTS5_DATA),
+       PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
+       PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
+       PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
+       PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
+       PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
+
+       /* PTT */
+       PINMUX_GPIO(GPIO_PTT7, PTT7_DATA),
+       PINMUX_GPIO(GPIO_PTT6, PTT6_DATA),
+       PINMUX_GPIO(GPIO_PTT5, PTT5_DATA),
+       PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
+       PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
+       PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
+       PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
+       PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
+
+       /* PTU */
+       PINMUX_GPIO(GPIO_PTU7, PTU7_DATA),
+       PINMUX_GPIO(GPIO_PTU6, PTU6_DATA),
+       PINMUX_GPIO(GPIO_PTU5, PTU5_DATA),
+       PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
+       PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
+       PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
+       PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
+       PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
+
+       /* PTV */
+       PINMUX_GPIO(GPIO_PTV7, PTV7_DATA),
+       PINMUX_GPIO(GPIO_PTV6, PTV6_DATA),
+       PINMUX_GPIO(GPIO_PTV5, PTV5_DATA),
+       PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
+       PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
+       PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
+       PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
+       PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
+
+       /* PTW */
+       PINMUX_GPIO(GPIO_PTW7, PTW7_DATA),
+       PINMUX_GPIO(GPIO_PTW6, PTW6_DATA),
+       PINMUX_GPIO(GPIO_PTW5, PTW5_DATA),
+       PINMUX_GPIO(GPIO_PTW4, PTW4_DATA),
+       PINMUX_GPIO(GPIO_PTW3, PTW3_DATA),
+       PINMUX_GPIO(GPIO_PTW2, PTW2_DATA),
+       PINMUX_GPIO(GPIO_PTW1, PTW1_DATA),
+       PINMUX_GPIO(GPIO_PTW0, PTW0_DATA),
+
+       /* PTX */
+       PINMUX_GPIO(GPIO_PTX7, PTX7_DATA),
+       PINMUX_GPIO(GPIO_PTX6, PTX6_DATA),
+       PINMUX_GPIO(GPIO_PTX5, PTX5_DATA),
+       PINMUX_GPIO(GPIO_PTX4, PTX4_DATA),
+       PINMUX_GPIO(GPIO_PTX3, PTX3_DATA),
+       PINMUX_GPIO(GPIO_PTX2, PTX2_DATA),
+       PINMUX_GPIO(GPIO_PTX1, PTX1_DATA),
+       PINMUX_GPIO(GPIO_PTX0, PTX0_DATA),
+
+       /* PTY */
+       PINMUX_GPIO(GPIO_PTY7, PTY7_DATA),
+       PINMUX_GPIO(GPIO_PTY6, PTY6_DATA),
+       PINMUX_GPIO(GPIO_PTY5, PTY5_DATA),
+       PINMUX_GPIO(GPIO_PTY4, PTY4_DATA),
+       PINMUX_GPIO(GPIO_PTY3, PTY3_DATA),
+       PINMUX_GPIO(GPIO_PTY2, PTY2_DATA),
+       PINMUX_GPIO(GPIO_PTY1, PTY1_DATA),
+       PINMUX_GPIO(GPIO_PTY0, PTY0_DATA),
+
+       /* PTZ */
+       PINMUX_GPIO(GPIO_PTZ7, PTZ7_DATA),
+       PINMUX_GPIO(GPIO_PTZ6, PTZ6_DATA),
+       PINMUX_GPIO(GPIO_PTZ5, PTZ5_DATA),
+       PINMUX_GPIO(GPIO_PTZ4, PTZ4_DATA),
+       PINMUX_GPIO(GPIO_PTZ3, PTZ3_DATA),
+       PINMUX_GPIO(GPIO_PTZ2, PTZ2_DATA),
+       PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
+       PINMUX_GPIO(GPIO_PTZ0, PTZ0_DATA),
+
+       /* BSC */
+       PINMUX_GPIO(GPIO_FN_D31,        D31_MARK),
+       PINMUX_GPIO(GPIO_FN_D30,        D30_MARK),
+       PINMUX_GPIO(GPIO_FN_D29,        D29_MARK),
+       PINMUX_GPIO(GPIO_FN_D28,        D28_MARK),
+       PINMUX_GPIO(GPIO_FN_D27,        D27_MARK),
+       PINMUX_GPIO(GPIO_FN_D26,        D26_MARK),
+       PINMUX_GPIO(GPIO_FN_D25,        D25_MARK),
+       PINMUX_GPIO(GPIO_FN_D24,        D24_MARK),
+       PINMUX_GPIO(GPIO_FN_D23,        D23_MARK),
+       PINMUX_GPIO(GPIO_FN_D22,        D22_MARK),
+       PINMUX_GPIO(GPIO_FN_D21,        D21_MARK),
+       PINMUX_GPIO(GPIO_FN_D20,        D20_MARK),
+       PINMUX_GPIO(GPIO_FN_D19,        D19_MARK),
+       PINMUX_GPIO(GPIO_FN_D18,        D18_MARK),
+       PINMUX_GPIO(GPIO_FN_D17,        D17_MARK),
+       PINMUX_GPIO(GPIO_FN_D16,        D16_MARK),
+       PINMUX_GPIO(GPIO_FN_D15,        D15_MARK),
+       PINMUX_GPIO(GPIO_FN_D14,        D14_MARK),
+       PINMUX_GPIO(GPIO_FN_D13,        D13_MARK),
+       PINMUX_GPIO(GPIO_FN_D12,        D12_MARK),
+       PINMUX_GPIO(GPIO_FN_D11,        D11_MARK),
+       PINMUX_GPIO(GPIO_FN_D10,        D10_MARK),
+       PINMUX_GPIO(GPIO_FN_D9,         D9_MARK),
+       PINMUX_GPIO(GPIO_FN_D8,         D8_MARK),
+       PINMUX_GPIO(GPIO_FN_D7,         D7_MARK),
+       PINMUX_GPIO(GPIO_FN_D6,         D6_MARK),
+       PINMUX_GPIO(GPIO_FN_D5,         D5_MARK),
+       PINMUX_GPIO(GPIO_FN_D4,         D4_MARK),
+       PINMUX_GPIO(GPIO_FN_D3,         D3_MARK),
+       PINMUX_GPIO(GPIO_FN_D2,         D2_MARK),
+       PINMUX_GPIO(GPIO_FN_D1,         D1_MARK),
+       PINMUX_GPIO(GPIO_FN_D0,         D0_MARK),
+       PINMUX_GPIO(GPIO_FN_A25,        A25_MARK),
+       PINMUX_GPIO(GPIO_FN_A24,        A24_MARK),
+       PINMUX_GPIO(GPIO_FN_A23,        A23_MARK),
+       PINMUX_GPIO(GPIO_FN_A22,        A22_MARK),
+       PINMUX_GPIO(GPIO_FN_CS6B_CE1B,  CS6B_CE1B_MARK),
+       PINMUX_GPIO(GPIO_FN_CS6A_CE2B,  CS6A_CE2B_MARK),
+       PINMUX_GPIO(GPIO_FN_CS5B_CE1A,  CS5B_CE1A_MARK),
+       PINMUX_GPIO(GPIO_FN_CS5A_CE2A,  CS5A_CE2A_MARK),
+       PINMUX_GPIO(GPIO_FN_WE3_ICIOWR, WE3_ICIOWR_MARK),
+       PINMUX_GPIO(GPIO_FN_WE2_ICIORD, WE2_ICIORD_MARK),
+       PINMUX_GPIO(GPIO_FN_IOIS16,     IOIS16_MARK),
+       PINMUX_GPIO(GPIO_FN_WAIT,       WAIT_MARK),
+       PINMUX_GPIO(GPIO_FN_BS,         BS_MARK),
+
+       /* KEYSC */
+       PINMUX_GPIO(GPIO_FN_KEYOUT5_IN5,        KEYOUT5_IN5_MARK),
+       PINMUX_GPIO(GPIO_FN_KEYOUT4_IN6,        KEYOUT4_IN6_MARK),
+       PINMUX_GPIO(GPIO_FN_KEYIN4,             KEYIN4_MARK),
+       PINMUX_GPIO(GPIO_FN_KEYIN3,             KEYIN3_MARK),
+       PINMUX_GPIO(GPIO_FN_KEYIN2,             KEYIN2_MARK),
+       PINMUX_GPIO(GPIO_FN_KEYIN1,             KEYIN1_MARK),
+       PINMUX_GPIO(GPIO_FN_KEYIN0,             KEYIN0_MARK),
+       PINMUX_GPIO(GPIO_FN_KEYOUT3,            KEYOUT3_MARK),
+       PINMUX_GPIO(GPIO_FN_KEYOUT2,            KEYOUT2_MARK),
+       PINMUX_GPIO(GPIO_FN_KEYOUT1,            KEYOUT1_MARK),
+       PINMUX_GPIO(GPIO_FN_KEYOUT0,            KEYOUT0_MARK),
+
+       /* ATAPI */
+       PINMUX_GPIO(GPIO_FN_IDED15,     IDED15_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED14,     IDED14_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED13,     IDED13_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED12,     IDED12_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED11,     IDED11_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED10,     IDED10_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED9,      IDED9_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED8,      IDED8_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED7,      IDED7_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED6,      IDED6_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED5,      IDED5_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED4,      IDED4_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED3,      IDED3_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED2,      IDED2_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED1,      IDED1_MARK),
+       PINMUX_GPIO(GPIO_FN_IDED0,      IDED0_MARK),
+       PINMUX_GPIO(GPIO_FN_IDEA2,      IDEA2_MARK),
+       PINMUX_GPIO(GPIO_FN_IDEA1,      IDEA1_MARK),
+       PINMUX_GPIO(GPIO_FN_IDEA0,      IDEA0_MARK),
+       PINMUX_GPIO(GPIO_FN_IDEIOWR,    IDEIOWR_MARK),
+       PINMUX_GPIO(GPIO_FN_IODREQ,     IODREQ_MARK),
+       PINMUX_GPIO(GPIO_FN_IDECS0,     IDECS0_MARK),
+       PINMUX_GPIO(GPIO_FN_IDECS1,     IDECS1_MARK),
+       PINMUX_GPIO(GPIO_FN_IDEIORD,    IDEIORD_MARK),
+       PINMUX_GPIO(GPIO_FN_DIRECTION,  DIRECTION_MARK),
+       PINMUX_GPIO(GPIO_FN_EXBUF_ENB,  EXBUF_ENB_MARK),
+       PINMUX_GPIO(GPIO_FN_IDERST,     IDERST_MARK),
+       PINMUX_GPIO(GPIO_FN_IODACK,     IODACK_MARK),
+       PINMUX_GPIO(GPIO_FN_IDEINT,     IDEINT_MARK),
+       PINMUX_GPIO(GPIO_FN_IDEIORDY,   IDEIORDY_MARK),
+
+       /* TPU */
+       PINMUX_GPIO(GPIO_FN_TPUTO3,     TPUTO3_MARK),
+       PINMUX_GPIO(GPIO_FN_TPUTO2,     TPUTO2_MARK),
+       PINMUX_GPIO(GPIO_FN_TPUTO1,     TPUTO1_MARK),
+       PINMUX_GPIO(GPIO_FN_TPUTO0,     TPUTO0_MARK),
+       PINMUX_GPIO(GPIO_FN_TPUTI3,     TPUTI3_MARK),
+       PINMUX_GPIO(GPIO_FN_TPUTI2,     TPUTI2_MARK),
+
+       /* LCDC */
+       PINMUX_GPIO(GPIO_FN_LCDD23,     LCDD23_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD22,     LCDD22_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD21,     LCDD21_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD20,     LCDD20_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD19,     LCDD19_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD18,     LCDD18_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD17,     LCDD17_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD16,     LCDD16_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD15,     LCDD15_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD14,     LCDD14_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD13,     LCDD13_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD12,     LCDD12_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD11,     LCDD11_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD10,     LCDD10_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD9,      LCDD9_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD8,      LCDD8_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD7,      LCDD7_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD6,      LCDD6_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD5,      LCDD5_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD4,      LCDD4_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD3,      LCDD3_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD2,      LCDD2_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD1,      LCDD1_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDD0,      LCDD0_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDVSYN,    LCDVSYN_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDDISP,    LCDDISP_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDRS,      LCDRS_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDHSYN,    LCDHSYN_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDCS,      LCDCS_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDDON,     LCDDON_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDDCK,     LCDDCK_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDWR,      LCDWR_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDVEPWC,   LCDVEPWC_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDVCPWC,   LCDVCPWC_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDRD,      LCDRD_MARK),
+       PINMUX_GPIO(GPIO_FN_LCDLCLK,    LCDLCLK_MARK),
+
+       /* SCIF0 */
+       PINMUX_GPIO(GPIO_FN_SCIF0_TXD,  SCIF0_TXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF0_RXD,  SCIF0_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF0_SCK,  SCIF0_SCK_MARK),
+
+       /* SCIF1 */
+       PINMUX_GPIO(GPIO_FN_SCIF1_SCK,  SCIF1_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF1_RXD,  SCIF1_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF1_TXD,  SCIF1_TXD_MARK),
+
+       /* SCIF2 */
+       PINMUX_GPIO(GPIO_FN_SCIF2_L_TXD,        SCIF2_L_TXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF2_L_SCK,        SCIF2_L_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF2_L_RXD,        SCIF2_L_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF2_V_TXD,        SCIF2_V_TXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF2_V_SCK,        SCIF2_V_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF2_V_RXD,        SCIF2_V_RXD_MARK),
+
+       /* SCIF3 */
+       PINMUX_GPIO(GPIO_FN_SCIF3_V_SCK,        SCIF3_V_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF3_V_RXD,        SCIF3_V_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF3_V_TXD,        SCIF3_V_TXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF3_V_CTS,        SCIF3_V_CTS_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF3_V_RTS,        SCIF3_V_RTS_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF3_I_SCK,        SCIF3_I_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF3_I_RXD,        SCIF3_I_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF3_I_TXD,        SCIF3_I_TXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF3_I_CTS,        SCIF3_I_CTS_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF3_I_RTS,        SCIF3_I_RTS_MARK),
+
+       /* SCIF4 */
+       PINMUX_GPIO(GPIO_FN_SCIF4_SCK,  SCIF4_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF4_RXD,  SCIF4_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF4_TXD,  SCIF4_TXD_MARK),
+
+       /* SCIF5 */
+       PINMUX_GPIO(GPIO_FN_SCIF5_SCK,  SCIF5_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF5_RXD,  SCIF5_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF5_TXD,  SCIF5_TXD_MARK),
+
+       /* FSI */
+       PINMUX_GPIO(GPIO_FN_FSIMCKB,    FSIMCKB_MARK),
+       PINMUX_GPIO(GPIO_FN_FSIMCKA,    FSIMCKA_MARK),
+       PINMUX_GPIO(GPIO_FN_FSIOASD,    FSIOASD_MARK),
+       PINMUX_GPIO(GPIO_FN_FSIIABCK,   FSIIABCK_MARK),
+       PINMUX_GPIO(GPIO_FN_FSIIALRCK,  FSIIALRCK_MARK),
+       PINMUX_GPIO(GPIO_FN_FSIOABCK,   FSIOABCK_MARK),
+       PINMUX_GPIO(GPIO_FN_FSIOALRCK,  FSIOALRCK_MARK),
+       PINMUX_GPIO(GPIO_FN_CLKAUDIOAO, CLKAUDIOAO_MARK),
+       PINMUX_GPIO(GPIO_FN_FSIIBSD,    FSIIBSD_MARK),
+       PINMUX_GPIO(GPIO_FN_FSIOBSD,    FSIOBSD_MARK),
+       PINMUX_GPIO(GPIO_FN_FSIIBBCK,   FSIIBBCK_MARK),
+       PINMUX_GPIO(GPIO_FN_FSIIBLRCK,  FSIIBLRCK_MARK),
+       PINMUX_GPIO(GPIO_FN_FSIOBBCK,   FSIOBBCK_MARK),
+       PINMUX_GPIO(GPIO_FN_FSIOBLRCK,  FSIOBLRCK_MARK),
+       PINMUX_GPIO(GPIO_FN_CLKAUDIOBO, CLKAUDIOBO_MARK),
+       PINMUX_GPIO(GPIO_FN_FSIIASD,    FSIIASD_MARK),
+
+       /* AUD */
+       PINMUX_GPIO(GPIO_FN_AUDCK,      AUDCK_MARK),
+       PINMUX_GPIO(GPIO_FN_AUDSYNC,    AUDSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_AUDATA3,    AUDATA3_MARK),
+       PINMUX_GPIO(GPIO_FN_AUDATA2,    AUDATA2_MARK),
+       PINMUX_GPIO(GPIO_FN_AUDATA1,    AUDATA1_MARK),
+       PINMUX_GPIO(GPIO_FN_AUDATA0,    AUDATA0_MARK),
+
+       /* VIO */
+       PINMUX_GPIO(GPIO_FN_VIO_CKO,    VIO_CKO_MARK),
+
+       /* VIO0 */
+       PINMUX_GPIO(GPIO_FN_VIO0_D15,   VIO0_D15_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D14,   VIO0_D14_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D13,   VIO0_D13_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D12,   VIO0_D12_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D11,   VIO0_D11_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D10,   VIO0_D10_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D9,    VIO0_D9_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D8,    VIO0_D8_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D7,    VIO0_D7_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D6,    VIO0_D6_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D5,    VIO0_D5_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D4,    VIO0_D4_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D3,    VIO0_D3_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D2,    VIO0_D2_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D1,    VIO0_D1_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_D0,    VIO0_D0_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_VD,    VIO0_VD_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_CLK,   VIO0_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_FLD,   VIO0_FLD_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO0_HD,    VIO0_HD_MARK),
+
+       /* VIO1 */
+       PINMUX_GPIO(GPIO_FN_VIO1_D7,    VIO1_D7_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO1_D6,    VIO1_D6_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO1_D5,    VIO1_D5_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO1_D4,    VIO1_D4_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO1_D3,    VIO1_D3_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO1_D2,    VIO1_D2_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO1_D1,    VIO1_D1_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO1_D0,    VIO1_D0_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO1_FLD,   VIO1_FLD_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO1_HD,    VIO1_HD_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO1_VD,    VIO1_VD_MARK),
+       PINMUX_GPIO(GPIO_FN_VIO1_CLK,   VIO1_CLK_MARK),
+
+       /* Eth */
+       PINMUX_GPIO(GPIO_FN_RMII_RXD0,          RMII_RXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII_RXD1,          RMII_RXD1_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII_TXD0,          RMII_TXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII_TXD1,          RMII_TXD1_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII_REF_CLK,       RMII_REF_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII_TX_EN,         RMII_TX_EN_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII_RX_ER,         RMII_RX_ER_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII_CRS_DV,        RMII_CRS_DV_MARK),
+       PINMUX_GPIO(GPIO_FN_LNKSTA,             LNKSTA_MARK),
+       PINMUX_GPIO(GPIO_FN_MDIO,               MDIO_MARK),
+       PINMUX_GPIO(GPIO_FN_MDC,                MDC_MARK),
+
+       /* System */
+       PINMUX_GPIO(GPIO_FN_PDSTATUS,   PDSTATUS_MARK),
+       PINMUX_GPIO(GPIO_FN_STATUS2,    STATUS2_MARK),
+       PINMUX_GPIO(GPIO_FN_STATUS0,    STATUS0_MARK),
+
+       /* VOU */
+       PINMUX_GPIO(GPIO_FN_DV_D15,     DV_D15_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D14,     DV_D14_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D13,     DV_D13_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D12,     DV_D12_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D11,     DV_D11_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D10,     DV_D10_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D9,      DV_D9_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D8,      DV_D8_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D7,      DV_D7_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D6,      DV_D6_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D5,      DV_D5_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D4,      DV_D4_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D3,      DV_D3_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D2,      DV_D2_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D1,      DV_D1_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_D0,      DV_D0_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_CLKI,    DV_CLKI_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_CLK,     DV_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_VSYNC,   DV_VSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_HSYNC,   DV_HSYNC_MARK),
+
+       /* MSIOF0 */
+       PINMUX_GPIO(GPIO_FN_MSIOF0_RXD,         MSIOF0_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF0_TXD,         MSIOF0_TXD_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF0_MCK,         MSIOF0_MCK_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF0_TSCK,        MSIOF0_TSCK_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF0_SS1,         MSIOF0_SS1_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF0_SS2,         MSIOF0_SS2_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF0_TSYNC,       MSIOF0_TSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF0_RSCK,        MSIOF0_RSCK_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF0_RSYNC,       MSIOF0_RSYNC_MARK),
+
+       /* MSIOF1 */
+       PINMUX_GPIO(GPIO_FN_MSIOF1_RXD,         MSIOF1_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF1_TXD,         MSIOF1_TXD_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF1_MCK,         MSIOF1_MCK_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF1_TSCK,        MSIOF1_TSCK_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF1_SS1,         MSIOF1_SS1_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF1_SS2,         MSIOF1_SS2_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF1_TSYNC,       MSIOF1_TSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF1_RSCK,        MSIOF1_RSCK_MARK),
+       PINMUX_GPIO(GPIO_FN_MSIOF1_RSYNC,       MSIOF1_RSYNC_MARK),
+
+       /* DMAC */
+       PINMUX_GPIO(GPIO_FN_DMAC_DACK0, DMAC_DACK0_MARK),
+       PINMUX_GPIO(GPIO_FN_DMAC_DREQ0, DMAC_DREQ0_MARK),
+       PINMUX_GPIO(GPIO_FN_DMAC_DACK1, DMAC_DACK1_MARK),
+       PINMUX_GPIO(GPIO_FN_DMAC_DREQ1, DMAC_DREQ1_MARK),
+
+       /* SDHI0 */
+       PINMUX_GPIO(GPIO_FN_SDHI0CD,    SDHI0CD_MARK),
+       PINMUX_GPIO(GPIO_FN_SDHI0WP,    SDHI0WP_MARK),
+       PINMUX_GPIO(GPIO_FN_SDHI0CMD,   SDHI0CMD_MARK),
+       PINMUX_GPIO(GPIO_FN_SDHI0CLK,   SDHI0CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_SDHI0D3,    SDHI0D3_MARK),
+       PINMUX_GPIO(GPIO_FN_SDHI0D2,    SDHI0D2_MARK),
+       PINMUX_GPIO(GPIO_FN_SDHI0D1,    SDHI0D1_MARK),
+       PINMUX_GPIO(GPIO_FN_SDHI0D0,    SDHI0D0_MARK),
+
+       /* SDHI1 */
+       PINMUX_GPIO(GPIO_FN_SDHI1CD,    SDHI1CD_MARK),
+       PINMUX_GPIO(GPIO_FN_SDHI1WP,    SDHI1WP_MARK),
+       PINMUX_GPIO(GPIO_FN_SDHI1CMD,   SDHI1CMD_MARK),
+       PINMUX_GPIO(GPIO_FN_SDHI1CLK,   SDHI1CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_SDHI1D3,    SDHI1D3_MARK),
+       PINMUX_GPIO(GPIO_FN_SDHI1D2,    SDHI1D2_MARK),
+       PINMUX_GPIO(GPIO_FN_SDHI1D1,    SDHI1D1_MARK),
+       PINMUX_GPIO(GPIO_FN_SDHI1D0,    SDHI1D0_MARK),
+
+       /* MMC */
+       PINMUX_GPIO(GPIO_FN_MMC_D7,     MMC_D7_MARK),
+       PINMUX_GPIO(GPIO_FN_MMC_D6,     MMC_D6_MARK),
+       PINMUX_GPIO(GPIO_FN_MMC_D5,     MMC_D5_MARK),
+       PINMUX_GPIO(GPIO_FN_MMC_D4,     MMC_D4_MARK),
+       PINMUX_GPIO(GPIO_FN_MMC_D3,     MMC_D3_MARK),
+       PINMUX_GPIO(GPIO_FN_MMC_D2,     MMC_D2_MARK),
+       PINMUX_GPIO(GPIO_FN_MMC_D1,     MMC_D1_MARK),
+       PINMUX_GPIO(GPIO_FN_MMC_D0,     MMC_D0_MARK),
+       PINMUX_GPIO(GPIO_FN_MMC_CLK,    MMC_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_MMC_CMD,    MMC_CMD_MARK),
+
+       /* IrDA */
+       PINMUX_GPIO(GPIO_FN_IRDA_OUT,   IRDA_OUT_MARK),
+       PINMUX_GPIO(GPIO_FN_IRDA_IN,    IRDA_IN_MARK),
+
+       /* TSIF */
+       PINMUX_GPIO(GPIO_FN_TSIF_TS0_SDAT,      TSIF_TS0_SDAT_MARK),
+       PINMUX_GPIO(GPIO_FN_TSIF_TS0_SCK,       TSIF_TS0_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_TSIF_TS0_SDEN,      TSIF_TS0_SDEN_MARK),
+       PINMUX_GPIO(GPIO_FN_TSIF_TS0_SPSYNC,    TSIF_TS0_SPSYNC_MARK),
+
+       /* IRQ */
+       PINMUX_GPIO(GPIO_FN_INTC_IRQ7,  INTC_IRQ7_MARK),
+       PINMUX_GPIO(GPIO_FN_INTC_IRQ6,  INTC_IRQ6_MARK),
+       PINMUX_GPIO(GPIO_FN_INTC_IRQ5,  INTC_IRQ5_MARK),
+       PINMUX_GPIO(GPIO_FN_INTC_IRQ4,  INTC_IRQ4_MARK),
+       PINMUX_GPIO(GPIO_FN_INTC_IRQ3,  INTC_IRQ3_MARK),
+       PINMUX_GPIO(GPIO_FN_INTC_IRQ2,  INTC_IRQ2_MARK),
+       PINMUX_GPIO(GPIO_FN_INTC_IRQ1,  INTC_IRQ1_MARK),
+       PINMUX_GPIO(GPIO_FN_INTC_IRQ0,  INTC_IRQ0_MARK),
+ };
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+       { PINMUX_CFG_REG("PACR", 0xa4050100, 16, 2) {
+               PTA7_FN, PTA7_OUT, PTA7_IN_PU, PTA7_IN,
+               PTA6_FN, PTA6_OUT, PTA6_IN_PU, PTA6_IN,
+               PTA5_FN, PTA5_OUT, PTA5_IN_PU, PTA5_IN,
+               PTA4_FN, PTA4_OUT, PTA4_IN_PU, PTA4_IN,
+               PTA3_FN, PTA3_OUT, PTA3_IN_PU, PTA3_IN,
+               PTA2_FN, PTA2_OUT, PTA2_IN_PU, PTA2_IN,
+               PTA1_FN, PTA1_OUT, PTA1_IN_PU, PTA1_IN,
+               PTA0_FN, PTA0_OUT, PTA0_IN_PU, PTA0_IN }
+       },
+       { PINMUX_CFG_REG("PBCR", 0xa4050102, 16, 2) {
+               PTB7_FN, PTB7_OUT, PTB7_IN_PU, PTB7_IN,
+               PTB6_FN, PTB6_OUT, PTB6_IN_PU, PTB6_IN,
+               PTB5_FN, PTB5_OUT, PTB5_IN_PU, PTB5_IN,
+               PTB4_FN, PTB4_OUT, PTB4_IN_PU, PTB4_IN,
+               PTB3_FN, PTB3_OUT, PTB3_IN_PU, PTB3_IN,
+               PTB2_FN, PTB2_OUT, PTB2_IN_PU, PTB2_IN,
+               PTB1_FN, PTB1_OUT, PTB1_IN_PU, PTB1_IN,
+               PTB0_FN, PTB0_OUT, PTB0_IN_PU, PTB0_IN }
+       },
+       { PINMUX_CFG_REG("PCCR", 0xa4050104, 16, 2) {
+               PTC7_FN, PTC7_OUT, PTC7_IN_PU, PTC7_IN,
+               PTC6_FN, PTC6_OUT, PTC6_IN_PU, PTC6_IN,
+               PTC5_FN, PTC5_OUT, PTC5_IN_PU, PTC5_IN,
+               PTC4_FN, PTC4_OUT, PTC4_IN_PU, PTC4_IN,
+               PTC3_FN, PTC3_OUT, PTC3_IN_PU, PTC3_IN,
+               PTC2_FN, PTC2_OUT, PTC2_IN_PU, PTC2_IN,
+               PTC1_FN, PTC1_OUT, PTC1_IN_PU, PTC1_IN,
+               PTC0_FN, PTC0_OUT, PTC0_IN_PU, PTC0_IN }
+       },
+       { PINMUX_CFG_REG("PDCR", 0xa4050106, 16, 2) {
+               PTD7_FN, PTD7_OUT, PTD7_IN_PU, PTD7_IN,
+               PTD6_FN, PTD6_OUT, PTD6_IN_PU, PTD6_IN,
+               PTD5_FN, PTD5_OUT, PTD5_IN_PU, PTD5_IN,
+               PTD4_FN, PTD4_OUT, PTD4_IN_PU, PTD4_IN,
+               PTD3_FN, PTD3_OUT, PTD3_IN_PU, PTD3_IN,
+               PTD2_FN, PTD2_OUT, PTD2_IN_PU, PTD2_IN,
+               PTD1_FN, PTD1_OUT, PTD1_IN_PU, PTD1_IN,
+               PTD0_FN, PTD0_OUT, PTD0_IN_PU, PTD0_IN }
+       },
+       { PINMUX_CFG_REG("PECR", 0xa4050108, 16, 2) {
+               PTE7_FN, PTE7_OUT, PTE7_IN_PU, PTE7_IN,
+               PTE6_FN, PTE6_OUT, PTE6_IN_PU, PTE6_IN,
+               PTE5_FN, PTE5_OUT, PTE5_IN_PU, PTE5_IN,
+               PTE4_FN, PTE4_OUT, PTE4_IN_PU, PTE4_IN,
+               PTE3_FN, PTE3_OUT, PTE3_IN_PU, PTE3_IN,
+               PTE2_FN, PTE2_OUT, PTE2_IN_PU, PTE2_IN,
+               PTE1_FN, PTE1_OUT, PTE1_IN_PU, PTE1_IN,
+               PTE0_FN, PTE0_OUT, PTE0_IN_PU, PTE0_IN }
+       },
+       { PINMUX_CFG_REG("PFCR", 0xa405010a, 16, 2) {
+               PTF7_FN, PTF7_OUT, PTF7_IN_PU, PTF7_IN,
+               PTF6_FN, PTF6_OUT, PTF6_IN_PU, PTF6_IN,
+               PTF5_FN, PTF5_OUT, PTF5_IN_PU, PTF5_IN,
+               PTF4_FN, PTF4_OUT, PTF4_IN_PU, PTF4_IN,
+               PTF3_FN, PTF3_OUT, PTF3_IN_PU, PTF3_IN,
+               PTF2_FN, PTF2_OUT, PTF2_IN_PU, PTF2_IN,
+               PTF1_FN, PTF1_OUT, PTF1_IN_PU, PTF1_IN,
+               PTF0_FN, PTF0_OUT, PTF0_IN_PU, PTF0_IN }
+       },
+       { PINMUX_CFG_REG("PGCR", 0xa405010c, 16, 2) {
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               PTG5_FN, PTG5_OUT, 0, 0,
+               PTG4_FN, PTG4_OUT, 0, 0,
+               PTG3_FN, PTG3_OUT, 0, 0,
+               PTG2_FN, PTG2_OUT, 0, 0,
+               PTG1_FN, PTG1_OUT, 0, 0,
+               PTG0_FN, PTG0_OUT, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PHCR", 0xa405010e, 16, 2) {
+               PTH7_FN, PTH7_OUT, PTH7_IN_PU, PTH7_IN,
+               PTH6_FN, PTH6_OUT, PTH6_IN_PU, PTH6_IN,
+               PTH5_FN, PTH5_OUT, PTH5_IN_PU, PTH5_IN,
+               PTH4_FN, PTH4_OUT, PTH4_IN_PU, PTH4_IN,
+               PTH3_FN, PTH3_OUT, PTH3_IN_PU, PTH3_IN,
+               PTH2_FN, PTH2_OUT, PTH2_IN_PU, PTH2_IN,
+               PTH1_FN, PTH1_OUT, PTH1_IN_PU, PTH1_IN,
+               PTH0_FN, PTH0_OUT, PTH0_IN_PU, PTH0_IN }
+       },
+       { PINMUX_CFG_REG("PJCR", 0xa4050110, 16, 2) {
+               PTJ7_FN, PTJ7_OUT, 0, 0,
+               PTJ6_FN, PTJ6_OUT, 0, 0,
+               PTJ5_FN, PTJ5_OUT, 0, 0,
+               0, 0, 0, 0,
+               PTJ3_FN, PTJ3_OUT, PTJ3_IN_PU, PTJ3_IN,
+               PTJ2_FN, PTJ2_OUT, PTJ2_IN_PU, PTJ2_IN,
+               PTJ1_FN, PTJ1_OUT, PTJ1_IN_PU, PTJ1_IN,
+               PTJ0_FN, PTJ0_OUT, PTJ0_IN_PU, PTJ0_IN }
+       },
+       { PINMUX_CFG_REG("PKCR", 0xa4050112, 16, 2) {
+               PTK7_FN, PTK7_OUT, PTK7_IN_PU, PTK7_IN,
+               PTK6_FN, PTK6_OUT, PTK6_IN_PU, PTK6_IN,
+               PTK5_FN, PTK5_OUT, PTK5_IN_PU, PTK5_IN,
+               PTK4_FN, PTK4_OUT, PTK4_IN_PU, PTK4_IN,
+               PTK3_FN, PTK3_OUT, PTK3_IN_PU, PTK3_IN,
+               PTK2_FN, PTK2_OUT, PTK2_IN_PU, PTK2_IN,
+               PTK1_FN, PTK1_OUT, PTK1_IN_PU, PTK1_IN,
+               PTK0_FN, PTK0_OUT, PTK0_IN_PU, PTK0_IN }
+       },
+       { PINMUX_CFG_REG("PLCR", 0xa4050114, 16, 2) {
+               PTL7_FN, PTL7_OUT, PTL7_IN_PU, PTL7_IN,
+               PTL6_FN, PTL6_OUT, PTL6_IN_PU, PTL6_IN,
+               PTL5_FN, PTL5_OUT, PTL5_IN_PU, PTL5_IN,
+               PTL4_FN, PTL4_OUT, PTL4_IN_PU, PTL4_IN,
+               PTL3_FN, PTL3_OUT, PTL3_IN_PU, PTL3_IN,
+               PTL2_FN, PTL2_OUT, PTL2_IN_PU, PTL2_IN,
+               PTL1_FN, PTL1_OUT, PTL1_IN_PU, PTL1_IN,
+               PTL0_FN, PTL0_OUT, PTL0_IN_PU, PTL0_IN }
+       },
+       { PINMUX_CFG_REG("PMCR", 0xa4050116, 16, 2) {
+               PTM7_FN, PTM7_OUT, PTM7_IN_PU, PTM7_IN,
+               PTM6_FN, PTM6_OUT, PTM6_IN_PU, PTM6_IN,
+               PTM5_FN, PTM5_OUT, PTM5_IN_PU, PTM5_IN,
+               PTM4_FN, PTM4_OUT, PTM4_IN_PU, PTM4_IN,
+               PTM3_FN, PTM3_OUT, PTM3_IN_PU, PTM3_IN,
+               PTM2_FN, PTM2_OUT, PTM2_IN_PU, PTM2_IN,
+               PTM1_FN, PTM1_OUT, PTM1_IN_PU, PTM1_IN,
+               PTM0_FN, PTM0_OUT, PTM0_IN_PU, PTM0_IN }
+       },
+       { PINMUX_CFG_REG("PNCR", 0xa4050118, 16, 2) {
+               PTN7_FN, PTN7_OUT, PTN7_IN_PU, PTN7_IN,
+               PTN6_FN, PTN6_OUT, PTN6_IN_PU, PTN6_IN,
+               PTN5_FN, PTN5_OUT, PTN5_IN_PU, PTN5_IN,
+               PTN4_FN, PTN4_OUT, PTN4_IN_PU, PTN4_IN,
+               PTN3_FN, PTN3_OUT, PTN3_IN_PU, PTN3_IN,
+               PTN2_FN, PTN2_OUT, PTN2_IN_PU, PTN2_IN,
+               PTN1_FN, PTN1_OUT, PTN1_IN_PU, PTN1_IN,
+               PTN0_FN, PTN0_OUT, PTN0_IN_PU, PTN0_IN }
+       },
+       { PINMUX_CFG_REG("PQCR", 0xa405011a, 16, 2) {
+               PTQ7_FN, PTQ7_OUT, PTQ7_IN_PU, PTQ7_IN,
+               PTQ6_FN, PTQ6_OUT, PTQ6_IN_PU, PTQ6_IN,
+               PTQ5_FN, PTQ5_OUT, PTQ5_IN_PU, PTQ5_IN,
+               PTQ4_FN, PTQ4_OUT, PTQ4_IN_PU, PTQ4_IN,
+               PTQ3_FN, PTQ3_OUT, PTQ3_IN_PU, PTQ3_IN,
+               PTQ2_FN, PTQ2_OUT, PTQ2_IN_PU, PTQ2_IN,
+               PTQ1_FN, PTQ1_OUT, PTQ1_IN_PU, PTQ1_IN,
+               PTQ0_FN, PTQ0_OUT, PTQ0_IN_PU, PTQ0_IN }
+       },
+       { PINMUX_CFG_REG("PRCR", 0xa405011c, 16, 2) {
+               PTR7_FN, PTR7_OUT, PTR7_IN_PU, PTR7_IN,
+               PTR6_FN, PTR6_OUT, PTR6_IN_PU, PTR6_IN,
+               PTR5_FN, PTR5_OUT, PTR5_IN_PU, PTR5_IN,
+               PTR4_FN, PTR4_OUT, PTR4_IN_PU, PTR4_IN,
+               PTR3_FN, 0,        PTR3_IN_PU, PTR3_IN,
+               PTR2_FN, 0,        PTR2_IN_PU, PTR2_IN,
+               PTR1_FN, PTR1_OUT, PTR1_IN_PU, PTR1_IN,
+               PTR0_FN, PTR0_OUT, PTR0_IN_PU, PTR0_IN }
+       },
+       { PINMUX_CFG_REG("PSCR", 0xa405011e, 16, 2) {
+               0, 0, 0, 0,
+               PTS6_FN, PTS6_OUT, PTS6_IN_PU, PTS6_IN,
+               PTS5_FN, PTS5_OUT, PTS5_IN_PU, PTS5_IN,
+               PTS4_FN, PTS4_OUT, PTS4_IN_PU, PTS4_IN,
+               PTS3_FN, PTS3_OUT, PTS3_IN_PU, PTS3_IN,
+               PTS2_FN, PTS2_OUT, PTS2_IN_PU, PTS2_IN,
+               PTS1_FN, PTS1_OUT, PTS1_IN_PU, PTS1_IN,
+               PTS0_FN, PTS0_OUT, PTS0_IN_PU, PTS0_IN }
+       },
+       { PINMUX_CFG_REG("PTCR", 0xa4050140, 16, 2) {
+               PTT7_FN, PTT7_OUT, PTT7_IN_PU, PTT7_IN,
+               PTT6_FN, PTT6_OUT, PTT6_IN_PU, PTT6_IN,
+               PTT5_FN, PTT5_OUT, PTT5_IN_PU, PTT5_IN,
+               PTT4_FN, PTT4_OUT, PTT4_IN_PU, PTT4_IN,
+               PTT3_FN, PTT3_OUT, PTT3_IN_PU, PTT3_IN,
+               PTT2_FN, PTT2_OUT, PTT2_IN_PU, PTT2_IN,
+               PTT1_FN, PTT1_OUT, PTT1_IN_PU, PTT1_IN,
+               PTT0_FN, PTT0_OUT, PTT0_IN_PU, PTT0_IN }
+       },
+       { PINMUX_CFG_REG("PUCR", 0xa4050142, 16, 2) {
+               PTU7_FN, PTU7_OUT, PTU7_IN_PU, PTU7_IN,
+               PTU6_FN, PTU6_OUT, PTU6_IN_PU, PTU6_IN,
+               PTU5_FN, PTU5_OUT, PTU5_IN_PU, PTU5_IN,
+               PTU4_FN, PTU4_OUT, PTU4_IN_PU, PTU4_IN,
+               PTU3_FN, PTU3_OUT, PTU3_IN_PU, PTU3_IN,
+               PTU2_FN, PTU2_OUT, PTU2_IN_PU, PTU2_IN,
+               PTU1_FN, PTU1_OUT, PTU1_IN_PU, PTU1_IN,
+               PTU0_FN, PTU0_OUT, PTU0_IN_PU, PTU0_IN }
+       },
+       { PINMUX_CFG_REG("PVCR", 0xa4050144, 16, 2) {
+               PTV7_FN, PTV7_OUT, PTV7_IN_PU, PTV7_IN,
+               PTV6_FN, PTV6_OUT, PTV6_IN_PU, PTV6_IN,
+               PTV5_FN, PTV5_OUT, PTV5_IN_PU, PTV5_IN,
+               PTV4_FN, PTV4_OUT, PTV4_IN_PU, PTV4_IN,
+               PTV3_FN, PTV3_OUT, PTV3_IN_PU, PTV3_IN,
+               PTV2_FN, PTV2_OUT, PTV2_IN_PU, PTV2_IN,
+               PTV1_FN, PTV1_OUT, PTV1_IN_PU, PTV1_IN,
+               PTV0_FN, PTV0_OUT, PTV0_IN_PU, PTV0_IN }
+       },
+       { PINMUX_CFG_REG("PWCR", 0xa4050146, 16, 2) {
+               PTW7_FN, PTW7_OUT, PTW7_IN_PU, PTW7_IN,
+               PTW6_FN, PTW6_OUT, PTW6_IN_PU, PTW6_IN,
+               PTW5_FN, PTW5_OUT, PTW5_IN_PU, PTW5_IN,
+               PTW4_FN, PTW4_OUT, PTW4_IN_PU, PTW4_IN,
+               PTW3_FN, PTW3_OUT, PTW3_IN_PU, PTW3_IN,
+               PTW2_FN, PTW2_OUT, PTW2_IN_PU, PTW2_IN,
+               PTW1_FN, PTW1_OUT, PTW1_IN_PU, PTW1_IN,
+               PTW0_FN, PTW0_OUT, PTW0_IN_PU, PTW0_IN }
+       },
+       { PINMUX_CFG_REG("PXCR", 0xa4050148, 16, 2) {
+               PTX7_FN, PTX7_OUT, PTX7_IN_PU, PTX7_IN,
+               PTX6_FN, PTX6_OUT, PTX6_IN_PU, PTX6_IN,
+               PTX5_FN, PTX5_OUT, PTX5_IN_PU, PTX5_IN,
+               PTX4_FN, PTX4_OUT, PTX4_IN_PU, PTX4_IN,
+               PTX3_FN, PTX3_OUT, PTX3_IN_PU, PTX3_IN,
+               PTX2_FN, PTX2_OUT, PTX2_IN_PU, PTX2_IN,
+               PTX1_FN, PTX1_OUT, PTX1_IN_PU, PTX1_IN,
+               PTX0_FN, PTX0_OUT, PTX0_IN_PU, PTX0_IN }
+       },
+       { PINMUX_CFG_REG("PYCR", 0xa405014a, 16, 2) {
+               PTY7_FN, PTY7_OUT, PTY7_IN_PU, PTY7_IN,
+               PTY6_FN, PTY6_OUT, PTY6_IN_PU, PTY6_IN,
+               PTY5_FN, PTY5_OUT, PTY5_IN_PU, PTY5_IN,
+               PTY4_FN, PTY4_OUT, PTY4_IN_PU, PTY4_IN,
+               PTY3_FN, PTY3_OUT, PTY3_IN_PU, PTY3_IN,
+               PTY2_FN, PTY2_OUT, PTY2_IN_PU, PTY2_IN,
+               PTY1_FN, PTY1_OUT, PTY1_IN_PU, PTY1_IN,
+               PTY0_FN, PTY0_OUT, PTY0_IN_PU, PTY0_IN }
+       },
+       { PINMUX_CFG_REG("PZCR", 0xa405014c, 16, 2) {
+               PTZ7_FN, PTZ7_OUT, PTZ7_IN_PU, PTZ7_IN,
+               PTZ6_FN, PTZ6_OUT, PTZ6_IN_PU, PTZ6_IN,
+               PTZ5_FN, PTZ5_OUT, PTZ5_IN_PU, PTZ5_IN,
+               PTZ4_FN, PTZ4_OUT, PTZ4_IN_PU, PTZ4_IN,
+               PTZ3_FN, PTZ3_OUT, PTZ3_IN_PU, PTZ3_IN,
+               PTZ2_FN, PTZ2_OUT, PTZ2_IN_PU, PTZ2_IN,
+               PTZ1_FN, PTZ1_OUT, PTZ1_IN_PU, PTZ1_IN,
+               PTZ0_FN, PTZ0_OUT, PTZ0_IN_PU, PTZ0_IN }
+       },
+       { PINMUX_CFG_REG("PSELA", 0xa405014e, 16, 1) {
+               PSA15_0, PSA15_1,
+               PSA14_0, PSA14_1,
+               PSA13_0, PSA13_1,
+               PSA12_0, PSA12_1,
+               0, 0,
+               PSA10_0, PSA10_1,
+               PSA9_0,  PSA9_1,
+               PSA8_0,  PSA8_1,
+               PSA7_0,  PSA7_1,
+               PSA6_0,  PSA6_1,
+               PSA5_0,  PSA5_1,
+               0, 0,
+               PSA3_0,  PSA3_1,
+               PSA2_0,  PSA2_1,
+               PSA1_0,  PSA1_1,
+               PSA0_0,  PSA0_1}
+       },
+       { PINMUX_CFG_REG("PSELB", 0xa4050150, 16, 1) {
+               0, 0,
+               PSB14_0, PSB14_1,
+               PSB13_0, PSB13_1,
+               PSB12_0, PSB12_1,
+               PSB11_0, PSB11_1,
+               PSB10_0, PSB10_1,
+               PSB9_0,  PSB9_1,
+               PSB8_0,  PSB8_1,
+               PSB7_0,  PSB7_1,
+               PSB6_0,  PSB6_1,
+               PSB5_0,  PSB5_1,
+               PSB4_0,  PSB4_1,
+               PSB3_0,  PSB3_1,
+               PSB2_0,  PSB2_1,
+               PSB1_0,  PSB1_1,
+               PSB0_0,  PSB0_1}
+       },
+       { PINMUX_CFG_REG("PSELC", 0xa4050152, 16, 1) {
+               PSC15_0, PSC15_1,
+               PSC14_0, PSC14_1,
+               PSC13_0, PSC13_1,
+               PSC12_0, PSC12_1,
+               PSC11_0, PSC11_1,
+               PSC10_0, PSC10_1,
+               PSC9_0,  PSC9_1,
+               PSC8_0,  PSC8_1,
+               PSC7_0,  PSC7_1,
+               PSC6_0,  PSC6_1,
+               PSC5_0,  PSC5_1,
+               PSC4_0,  PSC4_1,
+               0, 0,
+               PSC2_0,  PSC2_1,
+               PSC1_0,  PSC1_1,
+               PSC0_0,  PSC0_1}
+       },
+       { PINMUX_CFG_REG("PSELD", 0xa4050154, 16, 1) {
+               PSD15_0, PSD15_1,
+               PSD14_0, PSD14_1,
+               PSD13_0, PSD13_1,
+               PSD12_0, PSD12_1,
+               PSD11_0, PSD11_1,
+               PSD10_0, PSD10_1,
+               PSD9_0,  PSD9_1,
+               PSD8_0,  PSD8_1,
+               PSD7_0,  PSD7_1,
+               PSD6_0,  PSD6_1,
+               PSD5_0,  PSD5_1,
+               PSD4_0,  PSD4_1,
+               PSD3_0,  PSD3_1,
+               PSD2_0,  PSD2_1,
+               PSD1_0,  PSD1_1,
+               PSD0_0,  PSD0_1}
+       },
+       { PINMUX_CFG_REG("PSELE", 0xa4050156, 16, 1) {
+               PSE15_0, PSE15_1,
+               PSE14_0, PSE14_1,
+               PSE13_0, PSE13_1,
+               PSE12_0, PSE12_1,
+               PSE11_0, PSE11_1,
+               PSE10_0, PSE10_1,
+               PSE9_0,  PSE9_1,
+               PSE8_0,  PSE8_1,
+               PSE7_0,  PSE7_1,
+               PSE6_0,  PSE6_1,
+               PSE5_0,  PSE5_1,
+               PSE4_0,  PSE4_1,
+               PSE3_0,  PSE3_1,
+               PSE2_0,  PSE2_1,
+               PSE1_0,  PSE1_1,
+               PSE0_0,  PSE0_1}
+       },
+       {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+       { PINMUX_DATA_REG("PADR", 0xa4050120, 8) {
+               PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
+               PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA }
+       },
+       { PINMUX_DATA_REG("PBDR", 0xa4050122, 8) {
+               PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
+               PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA }
+       },
+       { PINMUX_DATA_REG("PCDR", 0xa4050124, 8) {
+               PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
+               PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA }
+       },
+       { PINMUX_DATA_REG("PDDR", 0xa4050126, 8) {
+               PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
+               PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA }
+       },
+       { PINMUX_DATA_REG("PEDR", 0xa4050128, 8) {
+               PTE7_DATA, PTE6_DATA, PTE5_DATA, PTE4_DATA,
+               PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA }
+       },
+       { PINMUX_DATA_REG("PFDR", 0xa405012a, 8) {
+               PTF7_DATA, PTF6_DATA, PTF5_DATA, PTF4_DATA,
+               PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA }
+       },
+       { PINMUX_DATA_REG("PGDR", 0xa405012c, 8) {
+               0,         0,         PTG5_DATA, PTG4_DATA,
+               PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA }
+       },
+       { PINMUX_DATA_REG("PHDR", 0xa405012e, 8) {
+               PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
+               PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA }
+       },
+       { PINMUX_DATA_REG("PJDR", 0xa4050130, 8) {
+               PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, 0,
+               PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA }
+       },
+       { PINMUX_DATA_REG("PKDR", 0xa4050132, 8) {
+               PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
+               PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
+       },
+       { PINMUX_DATA_REG("PLDR", 0xa4050134, 8) {
+               PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+               PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA }
+       },
+       { PINMUX_DATA_REG("PMDR", 0xa4050136, 8) {
+               PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+               PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
+       },
+       { PINMUX_DATA_REG("PNDR", 0xa4050138, 8) {
+               PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+               PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA }
+       },
+       { PINMUX_DATA_REG("PQDR", 0xa405013a, 8) {
+               PTQ7_DATA, PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
+               PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA }
+       },
+       { PINMUX_DATA_REG("PRDR", 0xa405013c, 8) {
+               PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
+               PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA }
+       },
+       { PINMUX_DATA_REG("PSDR", 0xa405013e, 8) {
+               0,         PTS6_DATA, PTS5_DATA, PTS4_DATA,
+               PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
+       },
+       { PINMUX_DATA_REG("PTDR", 0xa4050160, 8) {
+               PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
+               PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
+       },
+       { PINMUX_DATA_REG("PUDR", 0xa4050162, 8) {
+               PTU7_DATA, PTU6_DATA, PTU5_DATA, PTU4_DATA,
+               PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA }
+       },
+       { PINMUX_DATA_REG("PVDR", 0xa4050164, 8) {
+               PTV7_DATA, PTV6_DATA, PTV5_DATA, PTV4_DATA,
+               PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA }
+       },
+       { PINMUX_DATA_REG("PWDR", 0xa4050166, 8) {
+               PTW7_DATA, PTW6_DATA, PTW5_DATA, PTW4_DATA,
+               PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA }
+       },
+       { PINMUX_DATA_REG("PXDR", 0xa4050168, 8) {
+               PTX7_DATA, PTX6_DATA, PTX5_DATA, PTX4_DATA,
+               PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA }
+       },
+       { PINMUX_DATA_REG("PYDR", 0xa405016a, 8) {
+               PTY7_DATA, PTY6_DATA, PTY5_DATA, PTY4_DATA,
+               PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA }
+       },
+       { PINMUX_DATA_REG("PZDR", 0xa405016c, 8) {
+               PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA,
+               PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA }
+       },
+       { },
+};
+
+static struct pinmux_info sh7724_pinmux_info = {
+       .name = "sh7724_pfc",
+       .reserved_id = PINMUX_RESERVED,
+       .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+       .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+       .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
+       .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+       .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+       .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+       .first_gpio = GPIO_PTA7,
+       .last_gpio = GPIO_FN_INTC_IRQ0,
+
+       .gpios = pinmux_gpios,
+       .cfg_regs = pinmux_config_regs,
+       .data_regs = pinmux_data_regs,
+
+       .gpio_data = pinmux_data,
+       .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
+
+static int __init plat_pinmux_setup(void)
+{
+       return register_pinmux(&sh7724_pinmux_info);
+}
+arch_initcall(plat_pinmux_setup);
index c1549382c87c01070b0467ea5771bfa25205a7ba..6307e087c8642f1527323414bf24d71a73dda184 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
-#include <linux/sh_cmt.h>
+#include <linux/sh_timer.h>
 #include <asm/clock.h>
 
 static struct resource iic0_resources[] = {
@@ -141,7 +141,7 @@ static struct platform_device jpu_device = {
        .num_resources  = ARRAY_SIZE(jpu_resources),
 };
 
-static struct sh_cmt_config cmt_platform_data = {
+static struct sh_timer_config cmt_platform_data = {
        .name = "CMT",
        .channel_offset = 0x60,
        .timer_bit = 5,
@@ -173,27 +173,123 @@ static struct platform_device cmt_device = {
        .num_resources  = ARRAY_SIZE(cmt_resources),
 };
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "tmu0",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xffd80008,
+               .end    = 0xffd80013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "tmu0",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xffd80014,
+               .end    = 0xffd8001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "tmu0",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xffd80020,
+               .end    = 0xffd8002b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xffe00000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 80, 80, 80, 80 },
+               .clk            = "scif0",
        }, {
                .mapbase        = 0xffe10000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 81, 81, 81, 81 },
+               .clk            = "scif1",
        }, {
                .mapbase        = 0xffe20000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 82, 82, 82, 82 },
+               .clk            = "scif2",
        }, {
                .mapbase        = 0xffe30000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 83, 83, 83, 83 },
+               .clk            = "scif3",
        }, {
                .flags = 0,
        }
@@ -209,6 +305,9 @@ static struct platform_device sci_device = {
 
 static struct platform_device *sh7343_devices[] __initdata = {
        &cmt_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
        &iic0_device,
        &iic1_device,
        &sci_device,
@@ -219,12 +318,6 @@ static struct platform_device *sh7343_devices[] __initdata = {
 
 static int __init sh7343_devices_setup(void)
 {
-       clk_always_enable("uram0"); /* URAM */
-       clk_always_enable("xymem0"); /* XYMEM */
-       clk_always_enable("veu0"); /* VEU */
-       clk_always_enable("vpu0"); /* VPU */
-       clk_always_enable("jpu0"); /* JPU */
-
        platform_resource_setup_memory(&vpu_device, "vpu", 1 << 20);
        platform_resource_setup_memory(&veu_device, "veu", 2 << 20);
        platform_resource_setup_memory(&jpu_device, "jpu", 2 << 20);
@@ -234,6 +327,19 @@ static int __init sh7343_devices_setup(void)
 }
 __initcall(sh7343_devices_setup);
 
+static struct platform_device *sh7343_early_devices[] __initdata = {
+       &cmt_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7343_early_devices,
+                                  ARRAY_SIZE(sh7343_early_devices));
+}
+
 enum {
        UNUSED = 0,
 
index 93ecf8ed5c6c346a60c166624c9278a134de46ac..318516f6bfad862911fe80a2daa14a935c9744be 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
-#include <linux/sh_cmt.h>
+#include <linux/sh_timer.h>
 #include <asm/clock.h>
 
 static struct resource iic_resources[] = {
@@ -148,7 +148,7 @@ static struct platform_device veu1_device = {
        .num_resources  = ARRAY_SIZE(veu1_resources),
 };
 
-static struct sh_cmt_config cmt_platform_data = {
+static struct sh_timer_config cmt_platform_data = {
        .name = "CMT",
        .channel_offset = 0x60,
        .timer_bit = 5,
@@ -180,12 +180,105 @@ static struct platform_device cmt_device = {
        .num_resources  = ARRAY_SIZE(cmt_resources),
 };
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "tmu0",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xffd80008,
+               .end    = 0xffd80013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "tmu0",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xffd80014,
+               .end    = 0xffd8001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "tmu0",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xffd80020,
+               .end    = 0xffd8002b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xffe00000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 80, 80, 80, 80 },
+               .clk            = "scif0",
        }, {
                .flags = 0,
        }
@@ -201,6 +294,9 @@ static struct platform_device sci_device = {
 
 static struct platform_device *sh7366_devices[] __initdata = {
        &cmt_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
        &iic_device,
        &sci_device,
        &usb_host_device,
@@ -211,12 +307,6 @@ static struct platform_device *sh7366_devices[] __initdata = {
 
 static int __init sh7366_devices_setup(void)
 {
-       clk_always_enable("rsmem0"); /* RSMEM */
-       clk_always_enable("xymem0"); /* XYMEM */
-       clk_always_enable("veu1"); /* VEU-2 */
-       clk_always_enable("veu0"); /* VEU-1 */
-       clk_always_enable("vpu0"); /* VPU */
-
        platform_resource_setup_memory(&vpu_device, "vpu", 2 << 20);
        platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20);
        platform_resource_setup_memory(&veu1_device, "veu1", 2 << 20);
@@ -226,6 +316,19 @@ static int __init sh7366_devices_setup(void)
 }
 __initcall(sh7366_devices_setup);
 
+static struct platform_device *sh7366_early_devices[] __initdata = {
+       &cmt_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7366_early_devices,
+                                  ARRAY_SIZE(sh7366_early_devices));
+}
+
 enum {
        UNUSED=0,
 
index 406747f07dc0e32eb630b09dfc1b86f898988cd5..ea524a2da3e477ffe15176a672b5936add4fa435 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/serial_sci.h>
 #include <linux/mm.h>
 #include <linux/uio_driver.h>
-#include <linux/sh_cmt.h>
+#include <linux/sh_timer.h>
 #include <asm/clock.h>
 #include <asm/mmzone.h>
 
@@ -177,13 +177,13 @@ static struct platform_device jpu_device = {
        .num_resources  = ARRAY_SIZE(jpu_resources),
 };
 
-static struct sh_cmt_config cmt_platform_data = {
+static struct sh_timer_config cmt_platform_data = {
        .name = "CMT",
        .channel_offset = 0x60,
        .timer_bit = 5,
        .clk = "cmt0",
        .clockevent_rating = 125,
-       .clocksource_rating = 200,
+       .clocksource_rating = 125,
 };
 
 static struct resource cmt_resources[] = {
@@ -209,24 +209,119 @@ static struct platform_device cmt_device = {
        .num_resources  = ARRAY_SIZE(cmt_resources),
 };
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "tmu0",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xffd80008,
+               .end    = 0xffd80013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "tmu0",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xffd80014,
+               .end    = 0xffd8001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "tmu0",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xffd80020,
+               .end    = 0xffd8002b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xffe00000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 80, 80, 80, 80 },
+               .clk            = "scif0",
        },
        {
                .mapbase        = 0xffe10000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 81, 81, 81, 81 },
+               .clk            = "scif1",
        },
        {
                .mapbase        = 0xffe20000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 82, 82, 82, 82 },
+               .clk            = "scif2",
        },
        {
                .flags = 0,
@@ -243,6 +338,9 @@ static struct platform_device sci_device = {
 
 static struct platform_device *sh7722_devices[] __initdata = {
        &cmt_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
        &rtc_device,
        &usbf_device,
        &iic_device,
@@ -254,12 +352,6 @@ static struct platform_device *sh7722_devices[] __initdata = {
 
 static int __init sh7722_devices_setup(void)
 {
-       clk_always_enable("uram0"); /* URAM */
-       clk_always_enable("xymem0"); /* XYMEM */
-       clk_always_enable("veu0"); /* VEU */
-       clk_always_enable("vpu0"); /* VPU */
-       clk_always_enable("jpu0"); /* JPU */
-
        platform_resource_setup_memory(&vpu_device, "vpu", 1 << 20);
        platform_resource_setup_memory(&veu_device, "veu", 2 << 20);
        platform_resource_setup_memory(&jpu_device, "jpu", 2 << 20);
@@ -269,6 +361,19 @@ static int __init sh7722_devices_setup(void)
 }
 __initcall(sh7722_devices_setup);
 
+static struct platform_device *sh7722_early_devices[] __initdata = {
+       &cmt_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7722_early_devices,
+                                  ARRAY_SIZE(sh7722_early_devices));
+}
+
 enum {
        UNUSED=0,
 
index a800466b938c27f43908f26a00379b6d3ac7b374..d8f4a13aeff9d120302136d2476a593cb452b819 100644 (file)
@@ -13,7 +13,8 @@
 #include <linux/mm.h>
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
-#include <linux/sh_cmt.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
 #include <asm/clock.h>
 #include <asm/mmzone.h>
 
@@ -101,13 +102,13 @@ static struct platform_device veu1_device = {
        .num_resources  = ARRAY_SIZE(veu1_resources),
 };
 
-static struct sh_cmt_config cmt_platform_data = {
+static struct sh_timer_config cmt_platform_data = {
        .name = "CMT",
        .channel_offset = 0x60,
        .timer_bit = 5,
        .clk = "cmt0",
        .clockevent_rating = 125,
-       .clocksource_rating = 200,
+       .clocksource_rating = 125,
 };
 
 static struct resource cmt_resources[] = {
@@ -133,37 +134,225 @@ static struct platform_device cmt_device = {
        .num_resources  = ARRAY_SIZE(cmt_resources),
 };
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "tmu0",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xffd80008,
+               .end    = 0xffd80013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "tmu0",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xffd80014,
+               .end    = 0xffd8001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "tmu0",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xffd80020,
+               .end    = 0xffd8002b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
+static struct sh_timer_config tmu3_platform_data = {
+       .name = "TMU3",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "tmu1",
+};
+
+static struct resource tmu3_resources[] = {
+       [0] = {
+               .name   = "TMU3",
+               .start  = 0xffd90008,
+               .end    = 0xffd90013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 57,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu3_device = {
+       .name           = "sh_tmu",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &tmu3_platform_data,
+       },
+       .resource       = tmu3_resources,
+       .num_resources  = ARRAY_SIZE(tmu3_resources),
+};
+
+static struct sh_timer_config tmu4_platform_data = {
+       .name = "TMU4",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "tmu1",
+};
+
+static struct resource tmu4_resources[] = {
+       [0] = {
+               .name   = "TMU4",
+               .start  = 0xffd90014,
+               .end    = 0xffd9001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 58,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu4_device = {
+       .name           = "sh_tmu",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &tmu4_platform_data,
+       },
+       .resource       = tmu4_resources,
+       .num_resources  = ARRAY_SIZE(tmu4_resources),
+};
+
+static struct sh_timer_config tmu5_platform_data = {
+       .name = "TMU5",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "tmu1",
+};
+
+static struct resource tmu5_resources[] = {
+       [0] = {
+               .name   = "TMU5",
+               .start  = 0xffd90020,
+               .end    = 0xffd9002b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 57,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu5_device = {
+       .name           = "sh_tmu",
+       .id             = 5,
+       .dev = {
+               .platform_data  = &tmu5_platform_data,
+       },
+       .resource       = tmu5_resources,
+       .num_resources  = ARRAY_SIZE(tmu5_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xffe00000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 80, 80, 80, 80 },
+               .clk            = "scif0",
        },{
                .mapbase        = 0xffe10000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 81, 81, 81, 81 },
+               .clk            = "scif1",
        },{
                .mapbase        = 0xffe20000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 82, 82, 82, 82 },
+               .clk            = "scif2",
        },{
                .mapbase        = 0xa4e30000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIFA,
                .irqs           = { 56, 56, 56, 56 },
+               .clk            = "scif3",
        },{
                .mapbase        = 0xa4e40000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIFA,
                .irqs           = { 88, 88, 88, 88 },
+               .clk            = "scif4",
        },{
                .mapbase        = 0xa4e50000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIFA,
                .irqs           = { 109, 109, 109, 109 },
+               .clk            = "scif5",
        }, {
                .flags = 0,
        }
@@ -255,6 +444,12 @@ static struct platform_device iic_device = {
 
 static struct platform_device *sh7723_devices[] __initdata = {
        &cmt_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
        &sci_device,
        &rtc_device,
        &iic_device,
@@ -266,11 +461,6 @@ static struct platform_device *sh7723_devices[] __initdata = {
 
 static int __init sh7723_devices_setup(void)
 {
-       clk_always_enable("meram0"); /* MERAM */
-       clk_always_enable("veu1"); /* VEU2H1 */
-       clk_always_enable("veu0"); /* VEU2H0 */
-       clk_always_enable("vpu0"); /* VPU */
-
        platform_resource_setup_memory(&vpu_device, "vpu", 2 << 20);
        platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20);
        platform_resource_setup_memory(&veu1_device, "veu1", 2 << 20);
@@ -280,6 +470,31 @@ static int __init sh7723_devices_setup(void)
 }
 __initcall(sh7723_devices_setup);
 
+static struct platform_device *sh7723_early_devices[] __initdata = {
+       &cmt_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7723_early_devices,
+                                  ARRAY_SIZE(sh7723_early_devices));
+}
+
+#define RAMCR_CACHE_L2FC       0x0002
+#define RAMCR_CACHE_L2E                0x0001
+#define L2_CACHE_ENABLE                (RAMCR_CACHE_L2E|RAMCR_CACHE_L2FC)
+void __uses_jump_to_uncached l2_cache_init(void)
+{
+       /* Enable L2 cache */
+       ctrl_outl(L2_CACHE_ENABLE, RAMCR);
+}
+
 enum {
        UNUSED=0,
 
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
new file mode 100644 (file)
index 0000000..e5ac9eb
--- /dev/null
@@ -0,0 +1,786 @@
+/*
+ * SH7724 Setup
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ *
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on SH7723 Setup
+ * Copyright (C) 2008  Paul Mundt
+ *
+ * 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.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/mm.h>
+#include <linux/serial_sci.h>
+#include <linux/uio_driver.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
+#include <asm/clock.h>
+#include <asm/mmzone.h>
+
+/* Serial */
+static struct plat_sci_port sci_platform_data[] = {
+       {
+               .mapbase        = 0xffe00000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 80, 80, 80, 80 },
+               .clk            = "scif0",
+       }, {
+               .mapbase        = 0xffe10000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 81, 81, 81, 81 },
+               .clk            = "scif1",
+       }, {
+               .mapbase        = 0xffe20000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 82, 82, 82, 82 },
+               .clk            = "scif2",
+       }, {
+               .mapbase        = 0xa4e30000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIFA,
+               .irqs           = { 56, 56, 56, 56 },
+               .clk            = "scif3",
+       }, {
+               .mapbase        = 0xa4e40000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIFA,
+               .irqs           = { 88, 88, 88, 88 },
+               .clk            = "scif4",
+       }, {
+               .mapbase        = 0xa4e50000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIFA,
+               .irqs           = { 109, 109, 109, 109 },
+               .clk            = "scif5",
+       }, {
+               .flags = 0,
+       }
+};
+
+static struct platform_device sci_device = {
+       .name           = "sh-sci",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = sci_platform_data,
+       },
+};
+
+/* RTC */
+static struct resource rtc_resources[] = {
+       [0] = {
+               .start  = 0xa465fec0,
+               .end    = 0xa465fec0 + 0x58 - 1,
+               .flags  = IORESOURCE_IO,
+       },
+       [1] = {
+               /* Period IRQ */
+               .start  = 69,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               /* Carry IRQ */
+               .start  = 70,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               /* Alarm IRQ */
+               .start  = 68,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device rtc_device = {
+       .name           = "sh-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(rtc_resources),
+       .resource       = rtc_resources,
+};
+
+/* I2C0 */
+static struct resource iic0_resources[] = {
+       [0] = {
+               .name   = "IIC0",
+               .start  = 0x04470000,
+               .end    = 0x04470018 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 96,
+               .end    = 99,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device iic0_device = {
+       .name           = "i2c-sh_mobile",
+       .id             = 0, /* "i2c0" clock */
+       .num_resources  = ARRAY_SIZE(iic0_resources),
+       .resource       = iic0_resources,
+};
+
+/* I2C1 */
+static struct resource iic1_resources[] = {
+       [0] = {
+               .name   = "IIC1",
+               .start  = 0x04750000,
+               .end    = 0x04750018 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 92,
+               .end    = 95,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device iic1_device = {
+       .name           = "i2c-sh_mobile",
+       .id             = 1, /* "i2c1" clock */
+       .num_resources  = ARRAY_SIZE(iic1_resources),
+       .resource       = iic1_resources,
+};
+
+/* VPU */
+static struct uio_info vpu_platform_data = {
+       .name = "VPU5F",
+       .version = "0",
+       .irq = 60,
+};
+
+static struct resource vpu_resources[] = {
+       [0] = {
+               .name   = "VPU",
+               .start  = 0xfe900000,
+               .end    = 0xfe902807,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               /* place holder for contiguous memory */
+       },
+};
+
+static struct platform_device vpu_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &vpu_platform_data,
+       },
+       .resource       = vpu_resources,
+       .num_resources  = ARRAY_SIZE(vpu_resources),
+};
+
+/* VEU0 */
+static struct uio_info veu0_platform_data = {
+       .name = "VEU3F0",
+       .version = "0",
+       .irq = 83,
+};
+
+static struct resource veu0_resources[] = {
+       [0] = {
+               .name   = "VEU3F0",
+               .start  = 0xfe920000,
+               .end    = 0xfe9200cb - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               /* place holder for contiguous memory */
+       },
+};
+
+static struct platform_device veu0_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &veu0_platform_data,
+       },
+       .resource       = veu0_resources,
+       .num_resources  = ARRAY_SIZE(veu0_resources),
+};
+
+/* VEU1 */
+static struct uio_info veu1_platform_data = {
+       .name = "VEU3F1",
+       .version = "0",
+       .irq = 54,
+};
+
+static struct resource veu1_resources[] = {
+       [0] = {
+               .name   = "VEU3F1",
+               .start  = 0xfe924000,
+               .end    = 0xfe9240cb - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               /* place holder for contiguous memory */
+       },
+};
+
+static struct platform_device veu1_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &veu1_platform_data,
+       },
+       .resource       = veu1_resources,
+       .num_resources  = ARRAY_SIZE(veu1_resources),
+};
+
+static struct sh_timer_config cmt_platform_data = {
+       .name = "CMT",
+       .channel_offset = 0x60,
+       .timer_bit = 5,
+       .clk = "cmt0",
+       .clockevent_rating = 125,
+       .clocksource_rating = 200,
+};
+
+static struct resource cmt_resources[] = {
+       [0] = {
+               .name   = "CMT",
+               .start  = 0x044a0060,
+               .end    = 0x044a006b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 104,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt_platform_data,
+       },
+       .resource       = cmt_resources,
+       .num_resources  = ARRAY_SIZE(cmt_resources),
+};
+
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "tmu0",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xffd80008,
+               .end    = 0xffd80013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "tmu0",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xffd80014,
+               .end    = 0xffd8001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "tmu0",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xffd80020,
+               .end    = 0xffd8002b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
+
+static struct sh_timer_config tmu3_platform_data = {
+       .name = "TMU3",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "tmu1",
+};
+
+static struct resource tmu3_resources[] = {
+       [0] = {
+               .name   = "TMU3",
+               .start  = 0xffd90008,
+               .end    = 0xffd90013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 57,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu3_device = {
+       .name           = "sh_tmu",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &tmu3_platform_data,
+       },
+       .resource       = tmu3_resources,
+       .num_resources  = ARRAY_SIZE(tmu3_resources),
+};
+
+static struct sh_timer_config tmu4_platform_data = {
+       .name = "TMU4",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "tmu1",
+};
+
+static struct resource tmu4_resources[] = {
+       [0] = {
+               .name   = "TMU4",
+               .start  = 0xffd90014,
+               .end    = 0xffd9001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 58,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu4_device = {
+       .name           = "sh_tmu",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &tmu4_platform_data,
+       },
+       .resource       = tmu4_resources,
+       .num_resources  = ARRAY_SIZE(tmu4_resources),
+};
+
+static struct sh_timer_config tmu5_platform_data = {
+       .name = "TMU5",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "tmu1",
+};
+
+static struct resource tmu5_resources[] = {
+       [0] = {
+               .name   = "TMU5",
+               .start  = 0xffd90020,
+               .end    = 0xffd9002b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 57,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu5_device = {
+       .name           = "sh_tmu",
+       .id             = 5,
+       .dev = {
+               .platform_data  = &tmu5_platform_data,
+       },
+       .resource       = tmu5_resources,
+       .num_resources  = ARRAY_SIZE(tmu5_resources),
+};
+
+/* JPU */
+static struct uio_info jpu_platform_data = {
+       .name = "JPU",
+       .version = "0",
+       .irq = 27,
+};
+
+static struct resource jpu_resources[] = {
+       [0] = {
+               .name   = "JPU",
+               .start  = 0xfe980000,
+               .end    = 0xfe9902d3,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               /* place holder for contiguous memory */
+       },
+};
+
+static struct platform_device jpu_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &jpu_platform_data,
+       },
+       .resource       = jpu_resources,
+       .num_resources  = ARRAY_SIZE(jpu_resources),
+};
+
+static struct platform_device *sh7724_devices[] __initdata = {
+       &cmt_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
+       &sci_device,
+       &rtc_device,
+       &iic0_device,
+       &iic1_device,
+       &vpu_device,
+       &veu0_device,
+       &veu1_device,
+       &jpu_device,
+};
+
+static int __init sh7724_devices_setup(void)
+{
+       platform_resource_setup_memory(&vpu_device, "vpu", 2 << 20);
+       platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20);
+       platform_resource_setup_memory(&veu1_device, "veu1", 2 << 20);
+       platform_resource_setup_memory(&jpu_device,  "jpu",  2 << 20);
+
+       return platform_add_devices(sh7724_devices,
+                                   ARRAY_SIZE(sh7724_devices));
+}
+device_initcall(sh7724_devices_setup);
+
+static struct platform_device *sh7724_early_devices[] __initdata = {
+       &cmt_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7724_early_devices,
+                                  ARRAY_SIZE(sh7724_early_devices));
+}
+
+#define RAMCR_CACHE_L2FC       0x0002
+#define RAMCR_CACHE_L2E                0x0001
+#define L2_CACHE_ENABLE                (RAMCR_CACHE_L2E|RAMCR_CACHE_L2FC)
+void __uses_jump_to_uncached l2_cache_init(void)
+{
+       /* Enable L2 cache */
+       ctrl_outl(L2_CACHE_ENABLE, RAMCR);
+}
+
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+       HUDI,
+       DMAC1A_DEI0, DMAC1A_DEI1, DMAC1A_DEI2, DMAC1A_DEI3,
+       _2DG_TRI, _2DG_INI, _2DG_CEI,
+       DMAC0A_DEI0, DMAC0A_DEI1, DMAC0A_DEI2, DMAC0A_DEI3,
+       VIO_CEU0, VIO_BEU0, VIO_VEU1, VIO_VOU,
+       SCIFA3,
+       VPU,
+       TPU,
+       CEU1,
+       BEU1,
+       USB0, USB1,
+       ATAPI,
+       RTC_ATI, RTC_PRI, RTC_CUI,
+       DMAC1B_DEI4, DMAC1B_DEI5, DMAC1B_DADERR,
+       DMAC0B_DEI4, DMAC0B_DEI5, DMAC0B_DADERR,
+       KEYSC,
+       SCIF_SCIF0, SCIF_SCIF1, SCIF_SCIF2,
+       VEU0,
+       MSIOF_MSIOFI0, MSIOF_MSIOFI1,
+       SPU_SPUI0, SPU_SPUI1,
+       SCIFA4,
+       ICB,
+       ETHI,
+       I2C1_ALI, I2C1_TACKI, I2C1_WAITI, I2C1_DTEI,
+       I2C0_ALI, I2C0_TACKI, I2C0_WAITI, I2C0_DTEI,
+       SDHI0_SDHII0, SDHI0_SDHII1, SDHI0_SDHII2, SDHI0_SDHII3,
+       CMT,
+       TSIF,
+       FSI,
+       SCIFA5,
+       TMU0_TUNI0, TMU0_TUNI1, TMU0_TUNI2,
+       IRDA,
+       SDHI1_SDHII0, SDHI1_SDHII1, SDHI1_SDHII2,
+       JPU,
+       _2DDMAC,
+       MMC_MMC2I, MMC_MMC3I,
+       LCDC,
+       TMU1_TUNI0, TMU1_TUNI1, TMU1_TUNI2,
+
+       /* interrupt groups */
+       DMAC1A, _2DG, DMAC0A, VIO, USB, RTC,
+       DMAC1B, DMAC0B, I2C0, I2C1, SDHI0, SDHI1, SPU, MMCIF,
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+       INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
+       INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
+       INTC_VECT(IRQ6, 0x6c0), INTC_VECT(IRQ7, 0x6e0),
+
+       INTC_VECT(DMAC1A_DEI0, 0x700),
+       INTC_VECT(DMAC1A_DEI1, 0x720),
+       INTC_VECT(DMAC1A_DEI2, 0x740),
+       INTC_VECT(DMAC1A_DEI3, 0x760),
+
+       INTC_VECT(_2DG_TRI, 0x780),
+       INTC_VECT(_2DG_INI, 0x7A0),
+       INTC_VECT(_2DG_CEI, 0x7C0),
+
+       INTC_VECT(DMAC0A_DEI0, 0x800),
+       INTC_VECT(DMAC0A_DEI1, 0x820),
+       INTC_VECT(DMAC0A_DEI2, 0x840),
+       INTC_VECT(DMAC0A_DEI3, 0x860),
+
+       INTC_VECT(VIO_CEU0, 0x880),
+       INTC_VECT(VIO_BEU0, 0x8A0),
+       INTC_VECT(VIO_VEU1, 0x8C0),
+       INTC_VECT(VIO_VOU,  0x8E0),
+
+       INTC_VECT(SCIFA3, 0x900),
+       INTC_VECT(VPU,    0x980),
+       INTC_VECT(TPU,    0x9A0),
+       INTC_VECT(CEU1,   0x9E0),
+       INTC_VECT(BEU1,   0xA00),
+       INTC_VECT(USB0,   0xA20),
+       INTC_VECT(USB1,   0xA40),
+       INTC_VECT(ATAPI,  0xA60),
+
+       INTC_VECT(RTC_ATI, 0xA80),
+       INTC_VECT(RTC_PRI, 0xAA0),
+       INTC_VECT(RTC_CUI, 0xAC0),
+
+       INTC_VECT(DMAC1B_DEI4, 0xB00),
+       INTC_VECT(DMAC1B_DEI5, 0xB20),
+       INTC_VECT(DMAC1B_DADERR, 0xB40),
+
+       INTC_VECT(DMAC0B_DEI4, 0xB80),
+       INTC_VECT(DMAC0B_DEI5, 0xBA0),
+       INTC_VECT(DMAC0B_DADERR, 0xBC0),
+
+       INTC_VECT(KEYSC,      0xBE0),
+       INTC_VECT(SCIF_SCIF0, 0xC00),
+       INTC_VECT(SCIF_SCIF1, 0xC20),
+       INTC_VECT(SCIF_SCIF2, 0xC40),
+       INTC_VECT(VEU0,       0xC60),
+       INTC_VECT(MSIOF_MSIOFI0, 0xC80),
+       INTC_VECT(MSIOF_MSIOFI1, 0xCA0),
+       INTC_VECT(SPU_SPUI0, 0xCC0),
+       INTC_VECT(SPU_SPUI1, 0xCE0),
+       INTC_VECT(SCIFA4,    0xD00),
+
+       INTC_VECT(ICB,  0xD20),
+       INTC_VECT(ETHI, 0xD60),
+
+       INTC_VECT(I2C1_ALI, 0xD80),
+       INTC_VECT(I2C1_TACKI, 0xDA0),
+       INTC_VECT(I2C1_WAITI, 0xDC0),
+       INTC_VECT(I2C1_DTEI, 0xDE0),
+
+       INTC_VECT(I2C0_ALI, 0xE00),
+       INTC_VECT(I2C0_TACKI, 0xE20),
+       INTC_VECT(I2C0_WAITI, 0xE40),
+       INTC_VECT(I2C0_DTEI, 0xE60),
+
+       INTC_VECT(SDHI0_SDHII0, 0xE80),
+       INTC_VECT(SDHI0_SDHII1, 0xEA0),
+       INTC_VECT(SDHI0_SDHII2, 0xEC0),
+       INTC_VECT(SDHI0_SDHII3, 0xEE0),
+
+       INTC_VECT(CMT,    0xF00),
+       INTC_VECT(TSIF,   0xF20),
+       INTC_VECT(FSI,    0xF80),
+       INTC_VECT(SCIFA5, 0xFA0),
+
+       INTC_VECT(TMU0_TUNI0, 0x400),
+       INTC_VECT(TMU0_TUNI1, 0x420),
+       INTC_VECT(TMU0_TUNI2, 0x440),
+
+       INTC_VECT(IRDA,    0x480),
+
+       INTC_VECT(SDHI1_SDHII0, 0x4E0),
+       INTC_VECT(SDHI1_SDHII1, 0x500),
+       INTC_VECT(SDHI1_SDHII2, 0x520),
+
+       INTC_VECT(JPU, 0x560),
+       INTC_VECT(_2DDMAC, 0x4A0),
+
+       INTC_VECT(MMC_MMC2I, 0x5A0),
+       INTC_VECT(MMC_MMC3I, 0x5C0),
+
+       INTC_VECT(LCDC, 0xF40),
+
+       INTC_VECT(TMU1_TUNI0, 0x920),
+       INTC_VECT(TMU1_TUNI1, 0x940),
+       INTC_VECT(TMU1_TUNI2, 0x960),
+};
+
+static struct intc_group groups[] __initdata = {
+       INTC_GROUP(DMAC1A, DMAC1A_DEI0, DMAC1A_DEI1, DMAC1A_DEI2, DMAC1A_DEI3),
+       INTC_GROUP(_2DG, _2DG_TRI, _2DG_INI, _2DG_CEI),
+       INTC_GROUP(DMAC0A, DMAC0A_DEI0, DMAC0A_DEI1, DMAC0A_DEI2, DMAC0A_DEI3),
+       INTC_GROUP(VIO, VIO_CEU0, VIO_BEU0, VIO_VEU1, VIO_VOU),
+       INTC_GROUP(USB, USB0, USB1),
+       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+       INTC_GROUP(DMAC1B, DMAC1B_DEI4, DMAC1B_DEI5, DMAC1B_DADERR),
+       INTC_GROUP(DMAC0B, DMAC0B_DEI4, DMAC0B_DEI5, DMAC0B_DADERR),
+       INTC_GROUP(I2C0, I2C0_ALI, I2C0_TACKI, I2C0_WAITI, I2C0_DTEI),
+       INTC_GROUP(I2C1, I2C1_ALI, I2C1_TACKI, I2C1_WAITI, I2C1_DTEI),
+       INTC_GROUP(SDHI0, SDHI0_SDHII0, SDHI0_SDHII1, SDHI0_SDHII2, SDHI0_SDHII3),
+       INTC_GROUP(SDHI1, SDHI1_SDHII0, SDHI1_SDHII1, SDHI1_SDHII2),
+       INTC_GROUP(SPU, SPU_SPUI0, SPU_SPUI1),
+       INTC_GROUP(MMCIF, MMC_MMC2I, MMC_MMC3I),
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+       { 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */
+         { 0, TMU1_TUNI2, TMU1_TUNI1, TMU1_TUNI0,
+           0, SDHI1_SDHII2, SDHI1_SDHII1, SDHI1_SDHII0 } },
+       { 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */
+         { VIO_VOU, VIO_VEU1, VIO_BEU0, VIO_CEU0,
+           DMAC0A_DEI3, DMAC0A_DEI2, DMAC0A_DEI1, DMAC0A_DEI0 } },
+       { 0xa4080088, 0xa40800c8, 8, /* IMR2 / IMCR2 */
+         { 0, 0, 0, VPU, ATAPI, ETHI, 0, SCIFA3 } },
+       { 0xa408008c, 0xa40800cc, 8, /* IMR3 / IMCR3 */
+         { DMAC1A_DEI3, DMAC1A_DEI2, DMAC1A_DEI1, DMAC1A_DEI0,
+           SPU_SPUI1, SPU_SPUI0, BEU1, IRDA } },
+       { 0xa4080090, 0xa40800d0, 8, /* IMR4 / IMCR4 */
+         { 0, TMU0_TUNI2, TMU0_TUNI1, TMU0_TUNI0,
+           JPU, 0, 0, LCDC } },
+       { 0xa4080094, 0xa40800d4, 8, /* IMR5 / IMCR5 */
+         { KEYSC, DMAC0B_DADERR, DMAC0B_DEI5, DMAC0B_DEI4,
+           VEU0, SCIF_SCIF2, SCIF_SCIF1, SCIF_SCIF0 } },
+       { 0xa4080098, 0xa40800d8, 8, /* IMR6 / IMCR6 */
+         { 0, 0, ICB, SCIFA4,
+           CEU1, 0, MSIOF_MSIOFI1, MSIOF_MSIOFI0 } },
+       { 0xa408009c, 0xa40800dc, 8, /* IMR7 / IMCR7 */
+         { I2C0_DTEI, I2C0_WAITI, I2C0_TACKI, I2C0_ALI,
+           I2C1_DTEI, I2C1_WAITI, I2C1_TACKI, I2C1_ALI } },
+       { 0xa40800a0, 0xa40800e0, 8, /* IMR8 / IMCR8 */
+         { SDHI0_SDHII3, SDHI0_SDHII2, SDHI0_SDHII1, SDHI0_SDHII0,
+           0, 0, SCIFA5, FSI } },
+       { 0xa40800a4, 0xa40800e4, 8, /* IMR9 / IMCR9 */
+         { 0, 0, 0, CMT, 0, USB1, USB0, 0 } },
+       { 0xa40800a8, 0xa40800e8, 8, /* IMR10 / IMCR10 */
+         { 0, DMAC1B_DADERR, DMAC1B_DEI5, DMAC1B_DEI4,
+           0, RTC_CUI, RTC_PRI, RTC_ATI } },
+       { 0xa40800ac, 0xa40800ec, 8, /* IMR11 / IMCR11 */
+         { 0, _2DG_CEI, _2DG_INI, _2DG_TRI,
+           0, TPU, 0, TSIF } },
+       { 0xa40800b0, 0xa40800f0, 8, /* IMR12 / IMCR12 */
+         { 0, 0, MMC_MMC3I, MMC_MMC2I, 0, 0, 0, _2DDMAC } },
+       { 0xa4140044, 0xa4140064, 8, /* INTMSK00 / INTMSKCLR00 */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xa4080000, 0, 16, 4, /* IPRA */ { TMU0_TUNI0, TMU0_TUNI1,
+                                            TMU0_TUNI2, IRDA } },
+       { 0xa4080004, 0, 16, 4, /* IPRB */ { JPU, LCDC, DMAC1A, BEU1 } },
+       { 0xa4080008, 0, 16, 4, /* IPRC */ { TMU1_TUNI0, TMU1_TUNI1,
+                                            TMU1_TUNI2, SPU } },
+       { 0xa408000c, 0, 16, 4, /* IPRD */ { 0, MMCIF, 0, ATAPI } },
+       { 0xa4080010, 0, 16, 4, /* IPRE */ { DMAC0A, VIO, SCIFA3, VPU } },
+       { 0xa4080014, 0, 16, 4, /* IPRF */ { KEYSC, DMAC0B, USB, CMT } },
+       { 0xa4080018, 0, 16, 4, /* IPRG */ { SCIF_SCIF0, SCIF_SCIF1,
+                                            SCIF_SCIF2, VEU0 } },
+       { 0xa408001c, 0, 16, 4, /* IPRH */ { MSIOF_MSIOFI0, MSIOF_MSIOFI1,
+                                            I2C1, I2C0 } },
+       { 0xa4080020, 0, 16, 4, /* IPRI */ { SCIFA4, ICB, TSIF, _2DG } },
+       { 0xa4080024, 0, 16, 4, /* IPRJ */ { CEU1, ETHI, FSI, SDHI1 } },
+       { 0xa4080028, 0, 16, 4, /* IPRK */ { RTC, DMAC1B, 0, SDHI0 } },
+       { 0xa408002c, 0, 16, 4, /* IPRL */ { SCIFA5, 0, TPU, _2DDMAC } },
+       { 0xa4140010, 0, 32, 4, /* INTPRI00 */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_sense_reg sense_registers[] __initdata = {
+       { 0xa414001c, 16, 2, /* ICR1 */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_mask_reg ack_registers[] __initdata = {
+       { 0xa4140024, 0, 8, /* INTREQ00 */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static DECLARE_INTC_DESC_ACK(intc_desc, "sh7724", vectors, groups,
+                            mask_registers, prio_registers, sense_registers,
+                            ack_registers);
+
+void __init plat_irq_setup(void)
+{
+       register_intc_controller(&intc_desc);
+}
index bdf0f61ae1eddd436d1326f1cddfbe19d3bf26b7..f1e0c0d36da74121e6a3d40933da1813c7bbe6e2 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/platform_device.h>
 #include <linux/init.h>
 #include <linux/serial.h>
+#include <linux/sh_timer.h>
 #include <linux/io.h>
 #include <linux/serial_sci.h>
 
@@ -113,7 +114,195 @@ static struct platform_device usbf_device = {
        .resource       = usbf_resources,
 };
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xffd80008,
+               .end    = 0xffd80013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 28,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xffd80014,
+               .end    = 0xffd8001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 29,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xffd80020,
+               .end    = 0xffd8002f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 30,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
+static struct sh_timer_config tmu3_platform_data = {
+       .name = "TMU3",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu3_resources[] = {
+       [0] = {
+               .name   = "TMU3",
+               .start  = 0xffd88008,
+               .end    = 0xffd88013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 96,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu3_device = {
+       .name           = "sh_tmu",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &tmu3_platform_data,
+       },
+       .resource       = tmu3_resources,
+       .num_resources  = ARRAY_SIZE(tmu3_resources),
+};
+
+static struct sh_timer_config tmu4_platform_data = {
+       .name = "TMU4",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu4_resources[] = {
+       [0] = {
+               .name   = "TMU4",
+               .start  = 0xffd88014,
+               .end    = 0xffd8801f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 97,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu4_device = {
+       .name           = "sh_tmu",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &tmu4_platform_data,
+       },
+       .resource       = tmu4_resources,
+       .num_resources  = ARRAY_SIZE(tmu4_resources),
+};
+
+static struct sh_timer_config tmu5_platform_data = {
+       .name = "TMU5",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu5_resources[] = {
+       [0] = {
+               .name   = "TMU5",
+               .start  = 0xffd88020,
+               .end    = 0xffd8802b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 98,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu5_device = {
+       .name           = "sh_tmu",
+       .id             = 5,
+       .dev = {
+               .platform_data  = &tmu5_platform_data,
+       },
+       .resource       = tmu5_resources,
+       .num_resources  = ARRAY_SIZE(tmu5_resources),
+};
+
 static struct platform_device *sh7763_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
        &rtc_device,
        &sci_device,
        &usb_ohci_device,
@@ -127,6 +316,21 @@ static int __init sh7763_devices_setup(void)
 }
 __initcall(sh7763_devices_setup);
 
+static struct platform_device *sh7763_early_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7763_early_devices,
+                                  ARRAY_SIZE(sh7763_early_devices));
+}
+
 enum {
        UNUSED = 0,
 
index b73578ee295d47c5335fcf8ec4b170b9b327ca77..1e86209db284357791338b5ba9f2bd771f7f358c 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
 
 static struct plat_sci_port sci_platform_data[] = {
        {
@@ -76,7 +78,288 @@ static struct platform_device sci_device = {
        },
 };
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xffd80008,
+               .end    = 0xffd80013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xffd80014,
+               .end    = 0xffd8001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xffd80020,
+               .end    = 0xffd8002f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
+static struct sh_timer_config tmu3_platform_data = {
+       .name = "TMU3",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu3_resources[] = {
+       [0] = {
+               .name   = "TMU3",
+               .start  = 0xffd81008,
+               .end    = 0xffd81013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 19,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu3_device = {
+       .name           = "sh_tmu",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &tmu3_platform_data,
+       },
+       .resource       = tmu3_resources,
+       .num_resources  = ARRAY_SIZE(tmu3_resources),
+};
+
+static struct sh_timer_config tmu4_platform_data = {
+       .name = "TMU4",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu4_resources[] = {
+       [0] = {
+               .name   = "TMU4",
+               .start  = 0xffd81014,
+               .end    = 0xffd8101f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 20,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu4_device = {
+       .name           = "sh_tmu",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &tmu4_platform_data,
+       },
+       .resource       = tmu4_resources,
+       .num_resources  = ARRAY_SIZE(tmu4_resources),
+};
+
+static struct sh_timer_config tmu5_platform_data = {
+       .name = "TMU5",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu5_resources[] = {
+       [0] = {
+               .name   = "TMU5",
+               .start  = 0xffd81020,
+               .end    = 0xffd8102f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 21,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu5_device = {
+       .name           = "sh_tmu",
+       .id             = 5,
+       .dev = {
+               .platform_data  = &tmu5_platform_data,
+       },
+       .resource       = tmu5_resources,
+       .num_resources  = ARRAY_SIZE(tmu5_resources),
+};
+
+static struct sh_timer_config tmu6_platform_data = {
+       .name = "TMU6",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu6_resources[] = {
+       [0] = {
+               .name   = "TMU6",
+               .start  = 0xffd82008,
+               .end    = 0xffd82013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 22,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu6_device = {
+       .name           = "sh_tmu",
+       .id             = 6,
+       .dev = {
+               .platform_data  = &tmu6_platform_data,
+       },
+       .resource       = tmu6_resources,
+       .num_resources  = ARRAY_SIZE(tmu6_resources),
+};
+
+static struct sh_timer_config tmu7_platform_data = {
+       .name = "TMU7",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu7_resources[] = {
+       [0] = {
+               .name   = "TMU7",
+               .start  = 0xffd82014,
+               .end    = 0xffd8201f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 23,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu7_device = {
+       .name           = "sh_tmu",
+       .id             = 7,
+       .dev = {
+               .platform_data  = &tmu7_platform_data,
+       },
+       .resource       = tmu7_resources,
+       .num_resources  = ARRAY_SIZE(tmu7_resources),
+};
+
+static struct sh_timer_config tmu8_platform_data = {
+       .name = "TMU8",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu8_resources[] = {
+       [0] = {
+               .name   = "TMU8",
+               .start  = 0xffd82020,
+               .end    = 0xffd8202b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 24,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu8_device = {
+       .name           = "sh_tmu",
+       .id             = 8,
+       .dev = {
+               .platform_data  = &tmu8_platform_data,
+       },
+       .resource       = tmu8_resources,
+       .num_resources  = ARRAY_SIZE(tmu8_resources),
+};
+
 static struct platform_device *sh7770_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
+       &tmu6_device,
+       &tmu7_device,
+       &tmu8_device,
        &sci_device,
 };
 
@@ -87,6 +370,269 @@ static int __init sh7770_devices_setup(void)
 }
 __initcall(sh7770_devices_setup);
 
+static struct platform_device *sh7770_early_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
+       &tmu6_device,
+       &tmu7_device,
+       &tmu8_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7770_early_devices,
+                                  ARRAY_SIZE(sh7770_early_devices));
+}
+
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+       IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+       IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+       IRL_HHLL, IRL_HHLH, IRL_HHHL,
+
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5,
+
+       GPIO,
+       TMU0, TMU1, TMU2, TMU2_TICPI,
+       TMU3, TMU4, TMU5, TMU5_TICPI,
+       TMU6, TMU7, TMU8,
+       HAC, IPI, SPDIF, HUDI, I2C,
+       DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
+       I2S0, I2S1, I2S2, I2S3,
+       SRC_RX, SRC_TX, SRC_SPDIF,
+       DU, VIDEO_IN, REMOTE, YUV, USB, ATAPI, CAN, GPS, GFX2D,
+       GFX3D_MBX, GFX3D_DMAC,
+       EXBUS_ATA,
+       SPI0, SPI1,
+       SCIF089, SCIF1234, SCIF567,
+       ADC,
+       BBDMAC_0_3, BBDMAC_4_7, BBDMAC_8_10, BBDMAC_11_14,
+       BBDMAC_15_18, BBDMAC_19_22, BBDMAC_23_26, BBDMAC_27,
+       BBDMAC_28, BBDMAC_29, BBDMAC_30, BBDMAC_31,
+
+       /* interrupt groups */
+       TMU, DMAC, I2S, SRC, GFX3D, SPI, SCIF, BBDMAC,
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_VECT(GPIO, 0x3e0),
+       INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+       INTC_VECT(TMU2, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
+       INTC_VECT(TMU3, 0x480), INTC_VECT(TMU4, 0x4a0),
+       INTC_VECT(TMU5, 0x4c0), INTC_VECT(TMU5_TICPI, 0x4e0),
+       INTC_VECT(TMU6, 0x500), INTC_VECT(TMU7, 0x520),
+       INTC_VECT(TMU8, 0x540),
+       INTC_VECT(HAC, 0x580), INTC_VECT(IPI, 0x5c0),
+       INTC_VECT(SPDIF, 0x5e0),
+       INTC_VECT(HUDI, 0x600), INTC_VECT(I2C, 0x620),
+       INTC_VECT(DMAC0_DMINT0, 0x640), INTC_VECT(DMAC0_DMINT1, 0x660),
+       INTC_VECT(DMAC0_DMINT2, 0x680),
+       INTC_VECT(I2S0, 0x6a0), INTC_VECT(I2S1, 0x6c0),
+       INTC_VECT(I2S2, 0x6e0), INTC_VECT(I2S3, 0x700),
+       INTC_VECT(SRC_RX, 0x720), INTC_VECT(SRC_TX, 0x740),
+       INTC_VECT(SRC_SPDIF, 0x760),
+       INTC_VECT(DU, 0x780), INTC_VECT(VIDEO_IN, 0x7a0),
+       INTC_VECT(REMOTE, 0x7c0), INTC_VECT(YUV, 0x7e0),
+       INTC_VECT(USB, 0x840), INTC_VECT(ATAPI, 0x860),
+       INTC_VECT(CAN, 0x880), INTC_VECT(GPS, 0x8a0),
+       INTC_VECT(GFX2D, 0x8c0),
+       INTC_VECT(GFX3D_MBX, 0x900), INTC_VECT(GFX3D_DMAC, 0x920),
+       INTC_VECT(EXBUS_ATA, 0x940),
+       INTC_VECT(SPI0, 0x960), INTC_VECT(SPI1, 0x980),
+       INTC_VECT(SCIF089, 0x9a0), INTC_VECT(SCIF1234, 0x9c0),
+       INTC_VECT(SCIF1234, 0x9e0), INTC_VECT(SCIF1234, 0xa00),
+       INTC_VECT(SCIF1234, 0xa20), INTC_VECT(SCIF567, 0xa40),
+       INTC_VECT(SCIF567, 0xa60), INTC_VECT(SCIF567, 0xa80),
+       INTC_VECT(SCIF089, 0xaa0), INTC_VECT(SCIF089, 0xac0),
+       INTC_VECT(ADC, 0xb20),
+       INTC_VECT(BBDMAC_0_3, 0xba0), INTC_VECT(BBDMAC_0_3, 0xbc0),
+       INTC_VECT(BBDMAC_0_3, 0xbe0), INTC_VECT(BBDMAC_0_3, 0xc00),
+       INTC_VECT(BBDMAC_4_7, 0xc20), INTC_VECT(BBDMAC_4_7, 0xc40),
+       INTC_VECT(BBDMAC_4_7, 0xc60), INTC_VECT(BBDMAC_4_7, 0xc80),
+       INTC_VECT(BBDMAC_8_10, 0xca0), INTC_VECT(BBDMAC_8_10, 0xcc0),
+       INTC_VECT(BBDMAC_8_10, 0xce0), INTC_VECT(BBDMAC_11_14, 0xd00),
+       INTC_VECT(BBDMAC_11_14, 0xd20), INTC_VECT(BBDMAC_11_14, 0xd40),
+       INTC_VECT(BBDMAC_11_14, 0xd60), INTC_VECT(BBDMAC_15_18, 0xd80),
+       INTC_VECT(BBDMAC_15_18, 0xda0), INTC_VECT(BBDMAC_15_18, 0xdc0),
+       INTC_VECT(BBDMAC_15_18, 0xde0), INTC_VECT(BBDMAC_19_22, 0xe00),
+       INTC_VECT(BBDMAC_19_22, 0xe20), INTC_VECT(BBDMAC_19_22, 0xe40),
+       INTC_VECT(BBDMAC_19_22, 0xe60), INTC_VECT(BBDMAC_23_26, 0xe80),
+       INTC_VECT(BBDMAC_23_26, 0xea0), INTC_VECT(BBDMAC_23_26, 0xec0),
+       INTC_VECT(BBDMAC_23_26, 0xee0), INTC_VECT(BBDMAC_27, 0xf00),
+       INTC_VECT(BBDMAC_28, 0xf20), INTC_VECT(BBDMAC_29, 0xf40),
+       INTC_VECT(BBDMAC_30, 0xf60), INTC_VECT(BBDMAC_31, 0xf80),
+};
+
+static struct intc_group groups[] __initdata = {
+       INTC_GROUP(TMU, TMU0, TMU1, TMU2, TMU2_TICPI, TMU3, TMU4, TMU5,
+                  TMU5_TICPI, TMU6, TMU7, TMU8),
+       INTC_GROUP(DMAC, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2),
+       INTC_GROUP(I2S, I2S0, I2S1, I2S2, I2S3),
+       INTC_GROUP(SRC, SRC_RX, SRC_TX, SRC_SPDIF),
+       INTC_GROUP(GFX3D, GFX3D_MBX, GFX3D_DMAC),
+       INTC_GROUP(SPI, SPI0, SPI1),
+       INTC_GROUP(SCIF, SCIF089, SCIF1234, SCIF567),
+       INTC_GROUP(BBDMAC,
+                  BBDMAC_0_3, BBDMAC_4_7, BBDMAC_8_10, BBDMAC_11_14,
+                  BBDMAC_15_18, BBDMAC_19_22, BBDMAC_23_26, BBDMAC_27,
+                  BBDMAC_28, BBDMAC_29, BBDMAC_30, BBDMAC_31),
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+       { 0xffe00040, 0xffe00044, 32, /* INT2MSKR / INT2MSKCR */
+         { 0, BBDMAC, ADC, SCIF, SPI, EXBUS_ATA, GFX3D, GFX2D,
+           GPS, CAN, ATAPI, USB, YUV, REMOTE, VIDEO_IN, DU, SRC, I2S,
+           DMAC, I2C, HUDI, SPDIF, IPI, HAC, TMU, GPIO } },
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xffe00000, 0, 32, 8, /* INT2PRI0 */ { GPIO, TMU0, 0, HAC } },
+       { 0xffe00004, 0, 32, 8, /* INT2PRI1 */ { IPI, SPDIF, HUDI, I2C } },
+       { 0xffe00008, 0, 32, 8, /* INT2PRI2 */ { DMAC, I2S, SRC, DU } },
+       { 0xffe0000c, 0, 32, 8, /* INT2PRI3 */ { VIDEO_IN, REMOTE, YUV, USB } },
+       { 0xffe00010, 0, 32, 8, /* INT2PRI4 */ { ATAPI, CAN, GPS, GFX2D } },
+       { 0xffe00014, 0, 32, 8, /* INT2PRI5 */ { 0, GFX3D, EXBUS_ATA, SPI } },
+       { 0xffe00018, 0, 32, 8, /* INT2PRI6 */ { SCIF1234, SCIF567, SCIF089 } },
+       { 0xffe0001c, 0, 32, 8, /* INT2PRI7 */ { ADC, 0, 0, BBDMAC_0_3 } },
+       { 0xffe00020, 0, 32, 8, /* INT2PRI8 */
+         { BBDMAC_4_7, BBDMAC_8_10, BBDMAC_11_14, BBDMAC_15_18 } },
+       { 0xffe00024, 0, 32, 8, /* INT2PRI9 */
+         { BBDMAC_19_22, BBDMAC_23_26, BBDMAC_27, BBDMAC_28 } },
+       { 0xffe00028, 0, 32, 8, /* INT2PRI10 */
+         { BBDMAC_29, BBDMAC_30, BBDMAC_31 } },
+       { 0xffe0002c, 0, 32, 8, /* INT2PRI11 */
+         { TMU1, TMU2, TMU2_TICPI, TMU3 } },
+       { 0xffe00030, 0, 32, 8, /* INT2PRI12 */
+         { TMU4, TMU5, TMU5_TICPI, TMU6 } },
+       { 0xffe00034, 0, 32, 8, /* INT2PRI13 */
+         { TMU7, TMU8 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7770", vectors, groups,
+                        mask_registers, prio_registers, NULL);
+
+/* Support for external interrupt pins in IRQ mode */
+static struct intc_vect irq_vectors[] __initdata = {
+       INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
+       INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
+       INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380),
+};
+
+static struct intc_mask_reg irq_mask_registers[] __initdata = {
+       { 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, } },
+};
+
+static struct intc_prio_reg irq_prio_registers[] __initdata = {
+       { 0xffd00010, 0, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3,
+                                              IRQ4, IRQ5, } },
+};
+
+static struct intc_sense_reg irq_sense_registers[] __initdata = {
+       { 0xffd0001c, 32, 2, /* ICR1 */   { IRQ0, IRQ1, IRQ2, IRQ3,
+                                           IRQ4, IRQ5, } },
+};
+
+static DECLARE_INTC_DESC(intc_irq_desc, "sh7770-irq", irq_vectors,
+                        NULL, irq_mask_registers, irq_prio_registers,
+                        irq_sense_registers);
+
+/* External interrupt pins in IRL mode */
+static struct intc_vect irl_vectors[] __initdata = {
+       INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
+       INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
+       INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
+       INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0),
+       INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320),
+       INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360),
+       INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0),
+       INTC_VECT(IRL_HHHL, 0x3c0),
+};
+
+static struct intc_mask_reg irl3210_mask_registers[] __initdata = {
+       { 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */
+         { IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+           IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+           IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+           IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
+};
+
+static struct intc_mask_reg irl7654_mask_registers[] __initdata = {
+       { 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+           IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+           IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+           IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+           IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
+};
+
+static DECLARE_INTC_DESC(intc_irl7654_desc, "sh7780-irl7654", irl_vectors,
+                        NULL, irl7654_mask_registers, NULL, NULL);
+
+static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7780-irl3210", irl_vectors,
+                        NULL, irl3210_mask_registers, NULL, NULL);
+
+#define INTC_ICR0      0xffd00000
+#define INTC_INTMSK0   0xffd00044
+#define INTC_INTMSK1   0xffd00048
+#define INTC_INTMSK2   0xffd40080
+#define INTC_INTMSKCLR1        0xffd00068
+#define INTC_INTMSKCLR2        0xffd40084
+
 void __init plat_irq_setup(void)
 {
+       /* disable IRQ7-0 */
+       ctrl_outl(0xff000000, INTC_INTMSK0);
+
+       /* disable IRL3-0 + IRL7-4 */
+       ctrl_outl(0xc0000000, INTC_INTMSK1);
+       ctrl_outl(0xfffefffe, INTC_INTMSK2);
+
+       /* select IRL mode for IRL3-0 + IRL7-4 */
+       ctrl_outl(ctrl_inl(INTC_ICR0) & ~0x00c00000, INTC_ICR0);
+
+       /* disable holding function, ie enable "SH-4 Mode" */
+       ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00200000, INTC_ICR0);
+
+       register_intc_controller(&intc_desc);
+}
+
+void __init plat_irq_setup_pins(int mode)
+{
+       switch (mode) {
+       case IRQ_MODE_IRQ:
+               /* select IRQ mode for IRL3-0 + IRL7-4 */
+               ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00c00000, INTC_ICR0);
+               register_intc_controller(&intc_irq_desc);
+               break;
+       case IRQ_MODE_IRL7654:
+               /* enable IRL7-4 but don't provide any masking */
+               ctrl_outl(0x40000000, INTC_INTMSKCLR1);
+               ctrl_outl(0x0000fffe, INTC_INTMSKCLR2);
+               break;
+       case IRQ_MODE_IRL3210:
+               /* enable IRL0-3 but don't provide any masking */
+               ctrl_outl(0x80000000, INTC_INTMSKCLR1);
+               ctrl_outl(0xfffe0000, INTC_INTMSKCLR2);
+               break;
+       case IRQ_MODE_IRL7654_MASK:
+               /* enable IRL7-4 and mask using cpu intc controller */
+               ctrl_outl(0x40000000, INTC_INTMSKCLR1);
+               register_intc_controller(&intc_irl7654_desc);
+               break;
+       case IRQ_MODE_IRL3210_MASK:
+               /* enable IRL0-3 and mask using cpu intc controller */
+               ctrl_outl(0x80000000, INTC_INTMSKCLR1);
+               register_intc_controller(&intc_irl3210_desc);
+               break;
+       default:
+               BUG();
+       }
 }
index 6f7227cd65bffb6933d8395a0267b540b9959c6e..715e05b431e5e7f4b8c027f608803fab0d8edaba 100644 (file)
 #include <linux/serial.h>
 #include <linux/io.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
+
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xffd80008,
+               .end    = 0xffd80013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 28,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xffd80014,
+               .end    = 0xffd8001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 29,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xffd80020,
+               .end    = 0xffd8002f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 30,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
+static struct sh_timer_config tmu3_platform_data = {
+       .name = "TMU3",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu3_resources[] = {
+       [0] = {
+               .name   = "TMU3",
+               .start  = 0xffdc0008,
+               .end    = 0xffdc0013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 96,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu3_device = {
+       .name           = "sh_tmu",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &tmu3_platform_data,
+       },
+       .resource       = tmu3_resources,
+       .num_resources  = ARRAY_SIZE(tmu3_resources),
+};
+
+static struct sh_timer_config tmu4_platform_data = {
+       .name = "TMU4",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu4_resources[] = {
+       [0] = {
+               .name   = "TMU4",
+               .start  = 0xffdc0014,
+               .end    = 0xffdc001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 97,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu4_device = {
+       .name           = "sh_tmu",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &tmu4_platform_data,
+       },
+       .resource       = tmu4_resources,
+       .num_resources  = ARRAY_SIZE(tmu4_resources),
+};
+
+static struct sh_timer_config tmu5_platform_data = {
+       .name = "TMU5",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu5_resources[] = {
+       [0] = {
+               .name   = "TMU5",
+               .start  = 0xffdc0020,
+               .end    = 0xffdc002b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 98,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu5_device = {
+       .name           = "sh_tmu",
+       .id             = 5,
+       .dev = {
+               .platform_data  = &tmu5_platform_data,
+       },
+       .resource       = tmu5_resources,
+       .num_resources  = ARRAY_SIZE(tmu5_resources),
+};
 
 static struct resource rtc_resources[] = {
        [0] = {
@@ -58,6 +241,12 @@ static struct platform_device sci_device = {
 };
 
 static struct platform_device *sh7780_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
        &rtc_device,
        &sci_device,
 };
@@ -69,6 +258,21 @@ static int __init sh7780_devices_setup(void)
 }
 __initcall(sh7780_devices_setup);
 
+static struct platform_device *sh7780_early_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7780_early_devices,
+                                  ARRAY_SIZE(sh7780_early_devices));
+}
+
 enum {
        UNUSED = 0,
 
index d80802a49dbd1bd7c881ab572419f9ed9e9881ab..af561402570bdb411a026a1127b5e42a54fdc524 100644 (file)
 #include <linux/serial_sci.h>
 #include <linux/io.h>
 #include <linux/mm.h>
+#include <linux/sh_timer.h>
 #include <asm/mmzone.h>
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "tmu012_fck",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xffd80008,
+               .end    = 0xffd80013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 28,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "tmu012_fck",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xffd80014,
+               .end    = 0xffd8001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 29,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "tmu012_fck",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xffd80020,
+               .end    = 0xffd8002f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 30,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
+static struct sh_timer_config tmu3_platform_data = {
+       .name = "TMU3",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "tmu345_fck",
+};
+
+static struct resource tmu3_resources[] = {
+       [0] = {
+               .name   = "TMU3",
+               .start  = 0xffdc0008,
+               .end    = 0xffdc0013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 96,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu3_device = {
+       .name           = "sh_tmu",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &tmu3_platform_data,
+       },
+       .resource       = tmu3_resources,
+       .num_resources  = ARRAY_SIZE(tmu3_resources),
+};
+
+static struct sh_timer_config tmu4_platform_data = {
+       .name = "TMU4",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "tmu345_fck",
+};
+
+static struct resource tmu4_resources[] = {
+       [0] = {
+               .name   = "TMU4",
+               .start  = 0xffdc0014,
+               .end    = 0xffdc001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 97,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu4_device = {
+       .name           = "sh_tmu",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &tmu4_platform_data,
+       },
+       .resource       = tmu4_resources,
+       .num_resources  = ARRAY_SIZE(tmu4_resources),
+};
+
+static struct sh_timer_config tmu5_platform_data = {
+       .name = "TMU5",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "tmu345_fck",
+};
+
+static struct resource tmu5_resources[] = {
+       [0] = {
+               .name   = "TMU5",
+               .start  = 0xffdc0020,
+               .end    = 0xffdc002b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 98,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu5_device = {
+       .name           = "sh_tmu",
+       .id             = 5,
+       .dev = {
+               .platform_data  = &tmu5_platform_data,
+       },
+       .resource       = tmu5_resources,
+       .num_resources  = ARRAY_SIZE(tmu5_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xffea0000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 40, 40, 40, 40 },
+               .clk            = "scif_fck",
        }, {
                .mapbase        = 0xffeb0000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 44, 44, 44, 44 },
+               .clk            = "scif_fck",
        }, {
                .mapbase        = 0xffec0000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 60, 60, 60, 60 },
+               .clk            = "scif_fck",
        }, {
                .mapbase        = 0xffed0000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 61, 61, 61, 61 },
+               .clk            = "scif_fck",
        }, {
                .mapbase        = 0xffee0000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 62, 62, 62, 62 },
+               .clk            = "scif_fck",
        }, {
                .mapbase        = 0xffef0000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 63, 63, 63, 63 },
+               .clk            = "scif_fck",
        }, {
                .flags = 0,
        }
@@ -60,6 +249,12 @@ static struct platform_device sci_device = {
 };
 
 static struct platform_device *sh7785_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
        &sci_device,
 };
 
@@ -70,6 +265,21 @@ static int __init sh7785_devices_setup(void)
 }
 __initcall(sh7785_devices_setup);
 
+static struct platform_device *sh7785_early_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7785_early_devices,
+                                  ARRAY_SIZE(sh7785_early_devices));
+}
+
 enum {
        UNUSED = 0,
 
index 90e8cfff55fd4977def48d24a259d532726008e9..93e0d2c017e8235cbc7267244eb688e82a8b251c 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2009  Renesas Solutions Corp.
  * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ * Paul Mundt <paul.mundt@renesas.com>
  *
  * Based on SH7785 Setup
  *
@@ -19,6 +20,7 @@
 #include <linux/io.h>
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
+#include <linux/sh_timer.h>
 #include <asm/mmzone.h>
 
 static struct plat_sci_port sci_platform_data[] = {
@@ -69,6 +71,368 @@ static struct platform_device sci_device = {
        },
 };
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xffd80008,
+               .end    = 0xffd80013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xffd80014,
+               .end    = 0xffd8001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xffd80020,
+               .end    = 0xffd8002f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
+static struct sh_timer_config tmu3_platform_data = {
+       .name = "TMU3",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu3_resources[] = {
+       [0] = {
+               .name   = "TMU3",
+               .start  = 0xffda0008,
+               .end    = 0xffda0013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 20,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu3_device = {
+       .name           = "sh_tmu",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &tmu3_platform_data,
+       },
+       .resource       = tmu3_resources,
+       .num_resources  = ARRAY_SIZE(tmu3_resources),
+};
+
+static struct sh_timer_config tmu4_platform_data = {
+       .name = "TMU4",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu4_resources[] = {
+       [0] = {
+               .name   = "TMU4",
+               .start  = 0xffda0014,
+               .end    = 0xffda001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 21,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu4_device = {
+       .name           = "sh_tmu",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &tmu4_platform_data,
+       },
+       .resource       = tmu4_resources,
+       .num_resources  = ARRAY_SIZE(tmu4_resources),
+};
+
+static struct sh_timer_config tmu5_platform_data = {
+       .name = "TMU5",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu5_resources[] = {
+       [0] = {
+               .name   = "TMU5",
+               .start  = 0xffda0020,
+               .end    = 0xffda002b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 22,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu5_device = {
+       .name           = "sh_tmu",
+       .id             = 5,
+       .dev = {
+               .platform_data  = &tmu5_platform_data,
+       },
+       .resource       = tmu5_resources,
+       .num_resources  = ARRAY_SIZE(tmu5_resources),
+};
+
+static struct sh_timer_config tmu6_platform_data = {
+       .name = "TMU6",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu6_resources[] = {
+       [0] = {
+               .name   = "TMU6",
+               .start  = 0xffdc0008,
+               .end    = 0xffdc0013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 45,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu6_device = {
+       .name           = "sh_tmu",
+       .id             = 6,
+       .dev = {
+               .platform_data  = &tmu6_platform_data,
+       },
+       .resource       = tmu6_resources,
+       .num_resources  = ARRAY_SIZE(tmu6_resources),
+};
+
+static struct sh_timer_config tmu7_platform_data = {
+       .name = "TMU7",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu7_resources[] = {
+       [0] = {
+               .name   = "TMU7",
+               .start  = 0xffdc0014,
+               .end    = 0xffdc001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 45,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu7_device = {
+       .name           = "sh_tmu",
+       .id             = 7,
+       .dev = {
+               .platform_data  = &tmu7_platform_data,
+       },
+       .resource       = tmu7_resources,
+       .num_resources  = ARRAY_SIZE(tmu7_resources),
+};
+
+static struct sh_timer_config tmu8_platform_data = {
+       .name = "TMU8",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu8_resources[] = {
+       [0] = {
+               .name   = "TMU8",
+               .start  = 0xffdc0020,
+               .end    = 0xffdc002b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 45,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu8_device = {
+       .name           = "sh_tmu",
+       .id             = 8,
+       .dev = {
+               .platform_data  = &tmu8_platform_data,
+       },
+       .resource       = tmu8_resources,
+       .num_resources  = ARRAY_SIZE(tmu8_resources),
+};
+
+static struct sh_timer_config tmu9_platform_data = {
+       .name = "TMU9",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu9_resources[] = {
+       [0] = {
+               .name   = "TMU9",
+               .start  = 0xffde0008,
+               .end    = 0xffde0013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 46,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu9_device = {
+       .name           = "sh_tmu",
+       .id             = 9,
+       .dev = {
+               .platform_data  = &tmu9_platform_data,
+       },
+       .resource       = tmu9_resources,
+       .num_resources  = ARRAY_SIZE(tmu9_resources),
+};
+
+static struct sh_timer_config tmu10_platform_data = {
+       .name = "TMU10",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu10_resources[] = {
+       [0] = {
+               .name   = "TMU10",
+               .start  = 0xffde0014,
+               .end    = 0xffde001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 46,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu10_device = {
+       .name           = "sh_tmu",
+       .id             = 10,
+       .dev = {
+               .platform_data  = &tmu10_platform_data,
+       },
+       .resource       = tmu10_resources,
+       .num_resources  = ARRAY_SIZE(tmu10_resources),
+};
+
+static struct sh_timer_config tmu11_platform_data = {
+       .name = "TMU11",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu11_resources[] = {
+       [0] = {
+               .name   = "TMU11",
+               .start  = 0xffde0020,
+               .end    = 0xffde002b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 46,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu11_device = {
+       .name           = "sh_tmu",
+       .id             = 11,
+       .dev = {
+               .platform_data  = &tmu11_platform_data,
+       },
+       .resource       = tmu11_resources,
+       .num_resources  = ARRAY_SIZE(tmu11_resources),
+};
+
 static struct resource usb_ohci_resources[] = {
        [0] = {
                .start  = 0xffe70400,
@@ -94,6 +458,21 @@ static struct platform_device usb_ohci_device = {
        .resource       = usb_ohci_resources,
 };
 
+static struct platform_device *sh7786_early_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
+       &tmu6_device,
+       &tmu7_device,
+       &tmu8_device,
+       &tmu9_device,
+       &tmu10_device,
+       &tmu11_device,
+};
+
 static struct platform_device *sh7786_devices[] __initdata = {
        &sci_device,
        &usb_ohci_device,
@@ -156,12 +535,26 @@ static void __init sh7786_usb_setup(void)
 
 static int __init sh7786_devices_setup(void)
 {
+       int ret;
+
        sh7786_usb_setup();
+
+       ret = platform_add_devices(sh7786_early_devices,
+                                  ARRAY_SIZE(sh7786_early_devices));
+       if (unlikely(ret != 0))
+               return ret;
+
        return platform_add_devices(sh7786_devices,
                                    ARRAY_SIZE(sh7786_devices));
 }
 device_initcall(sh7786_devices_setup);
 
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7786_early_devices,
+                                  ARRAY_SIZE(sh7786_early_devices));
+}
+
 enum {
        UNUSED = 0,
 
index bd35f32534b98e11a3e231a16940931915995b43..53c65fd9ccef726d015cd71b664a151842e4731d 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * SH-X3 Setup
+ * SH-X3 Prototype Setup
  *
- *  Copyright (C) 2007  Paul Mundt
+ *  Copyright (C) 2007 - 2009  Paul Mundt
  *
  * 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
@@ -12,6 +12,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/io.h>
+#include <linux/sh_timer.h>
 #include <asm/mmzone.h>
 
 static struct plat_sci_port sci_platform_data[] = {
@@ -48,17 +49,221 @@ static struct platform_device sci_device = {
        },
 };
 
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = 0xffc10008,
+               .end    = 0xffc10013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 16,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = 0xffc10014,
+               .end    = 0xffc1001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 17,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = 0xffc10020,
+               .end    = 0xffc1002f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 18,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
+static struct sh_timer_config tmu3_platform_data = {
+       .name = "TMU3",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu3_resources[] = {
+       [0] = {
+               .name   = "TMU3",
+               .start  = 0xffc20008,
+               .end    = 0xffc20013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 19,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu3_device = {
+       .name           = "sh_tmu",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &tmu3_platform_data,
+       },
+       .resource       = tmu3_resources,
+       .num_resources  = ARRAY_SIZE(tmu3_resources),
+};
+
+static struct sh_timer_config tmu4_platform_data = {
+       .name = "TMU4",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu4_resources[] = {
+       [0] = {
+               .name   = "TMU4",
+               .start  = 0xffc20014,
+               .end    = 0xffc2001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 20,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu4_device = {
+       .name           = "sh_tmu",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &tmu4_platform_data,
+       },
+       .resource       = tmu4_resources,
+       .num_resources  = ARRAY_SIZE(tmu4_resources),
+};
+
+static struct sh_timer_config tmu5_platform_data = {
+       .name = "TMU5",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu5_resources[] = {
+       [0] = {
+               .name   = "TMU5",
+               .start  = 0xffc20020,
+               .end    = 0xffc2002b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 21,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu5_device = {
+       .name           = "sh_tmu",
+       .id             = 5,
+       .dev = {
+               .platform_data  = &tmu5_platform_data,
+       },
+       .resource       = tmu5_resources,
+       .num_resources  = ARRAY_SIZE(tmu5_resources),
+};
+
+static struct platform_device *shx3_early_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
+};
+
 static struct platform_device *shx3_devices[] __initdata = {
        &sci_device,
 };
 
 static int __init shx3_devices_setup(void)
 {
+       int ret;
+
+       ret = platform_add_devices(shx3_early_devices,
+                                  ARRAY_SIZE(shx3_early_devices));
+       if (unlikely(ret != 0))
+               return ret;
+
        return platform_add_devices(shx3_devices,
                                    ARRAY_SIZE(shx3_devices));
 }
 __initcall(shx3_devices_setup);
 
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(shx3_early_devices,
+                                  ARRAY_SIZE(shx3_early_devices));
+}
+
 enum {
        UNUSED = 0,
 
index ce4602ea23a81dbf1e49a4a55e5c2bdc766d535c..a184a31e686e03729bf0fa9e317105d0463419c2 100644 (file)
@@ -6,6 +6,9 @@ obj-y := entry.o probe.o switchto.o
 obj-$(CONFIG_SH_FPU)           += fpu.o
 obj-$(CONFIG_KALLSYMS)         += unwind.o
 
+# CPU subtype setup
+obj-$(CONFIG_CPU_SH5)          += setup-sh5.o
+
 # Primary on-chip clocks (common)
 clock-$(CONFIG_CPU_SH5)                := clock-sh5.o
 
index 52c49248833ac559d661ed1e979c1dc91bf2fa0a..7f864ebc51d3b054cb561826c69f577abc3ed144 100644 (file)
@@ -32,30 +32,30 @@ static struct clk_ops sh5_master_clk_ops = {
        .init           = master_clk_init,
 };
 
-static void module_clk_recalc(struct clk *clk)
+static unsigned long module_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(cprc_base) >> 12) & 0x0007;
-       clk->rate = clk->parent->rate / ifc_table[idx];
+       return clk->parent->rate / ifc_table[idx];
 }
 
 static struct clk_ops sh5_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
+static unsigned long bus_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(cprc_base) >> 3) & 0x0007;
-       clk->rate = clk->parent->rate / ifc_table[idx];
+       return clk->parent->rate / ifc_table[idx];
 }
 
 static struct clk_ops sh5_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
+static unsigned long cpu_clk_recalc(struct clk *clk)
 {
        int idx = (ctrl_inw(cprc_base) & 0x0007);
-       clk->rate = clk->parent->rate / ifc_table[idx];
+       return clk->parent->rate / ifc_table[idx];
 }
 
 static struct clk_ops sh5_cpu_clk_ops = {
@@ -71,7 +71,7 @@ static struct clk_ops *sh5_clk_ops[] = {
 
 void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
 {
-       cprc_base = onchip_remap(CPRC_BASE, 1024, "CPRC");
+       cprc_base = (unsigned long)ioremap_nocache(CPRC_BASE, 1024);
        BUG_ON(!cprc_base);
 
        if (idx < ARRAY_SIZE(sh5_clk_ops))
index 7e49cb812f8b6d16d9ec36e4814ee74c64ce0138..b0aacf675258f1f9a0a6ae166dbb5acc56ecad76 100644 (file)
@@ -812,27 +812,6 @@ no_underflow:
        ! exceptions
        add     SP, ZERO, r14
 
-#ifdef CONFIG_POOR_MANS_STRACE
-       /* We've pushed all the registers now, so only r2-r4 hold anything
-        * useful. Move them into callee save registers */
-       or      r2, ZERO, r28
-       or      r3, ZERO, r29
-       or      r4, ZERO, r30
-
-       /* Preserve r2 as the event code */
-       movi    evt_debug, r3
-       ori     r3, 1, r3
-       ptabs   r3, tr0
-
-       or      SP, ZERO, r6
-       getcon  TRA, r5
-       blink   tr0, LINK
-
-       or      r28, ZERO, r2
-       or      r29, ZERO, r3
-       or      r30, ZERO, r4
-#endif
-
        /* For syscall and debug race condition, get TRA now */
        getcon  TRA, r5
 
@@ -887,11 +866,6 @@ no_underflow:
  */
        .global ret_from_irq
 ret_from_irq:
-#ifdef CONFIG_POOR_MANS_STRACE
-       pta     evt_debug_ret_from_irq, tr0
-       ori     SP, 0, r2
-       blink   tr0, LINK
-#endif
        ld.q    SP, FRAME_S(FSSR), r6
        shlri   r6, 30, r6
        andi    r6, 1, r6
@@ -905,12 +879,6 @@ ret_from_irq:
 ret_from_exception:
        preempt_stop()
 
-#ifdef CONFIG_POOR_MANS_STRACE
-       pta     evt_debug_ret_from_exc, tr0
-       ori     SP, 0, r2
-       blink   tr0, LINK
-#endif
-
        ld.q    SP, FRAME_S(FSSR), r6
        shlri   r6, 30, r6
        andi    r6, 1, r6
@@ -1236,18 +1204,6 @@ syscall_bad:
        .global syscall_ret
 syscall_ret:
        st.q    SP, FRAME_R(9), r2      /* Expecting SP back to BASIC frame */
-
-#ifdef CONFIG_POOR_MANS_STRACE
-       /* nothing useful in registers at this point */
-
-       movi    evt_debug2, r5
-       ori     r5, 1, r5
-       ptabs   r5, tr0
-       ld.q    SP, FRAME_R(9), r2
-       or      SP, ZERO, r3
-       blink   tr0, LINK
-#endif
-
        ld.q    SP, FRAME_S(FSPC), r2
        addi    r2, 4, r2               /* Move PC, being pre-execution event */
        st.q    SP, FRAME_S(FSPC), r2
@@ -1268,25 +1224,12 @@ ret_from_fork:
        ptabs   r5, tr0
        blink   tr0, LINK
 
-#ifdef CONFIG_POOR_MANS_STRACE
-       /* nothing useful in registers at this point */
-
-       movi    evt_debug2, r5
-       ori     r5, 1, r5
-       ptabs   r5, tr0
-       ld.q    SP, FRAME_R(9), r2
-       or      SP, ZERO, r3
-       blink   tr0, LINK
-#endif
-
        ld.q    SP, FRAME_S(FSPC), r2
        addi    r2, 4, r2               /* Move PC, being pre-execution event */
        st.q    SP, FRAME_S(FSPC), r2
        pta     ret_from_syscall, tr0
        blink   tr0, ZERO
 
-
-
 syscall_allowed:
        /* Use LINK to deflect the exit point, default is syscall_ret */
        pta     syscall_ret, tr0
@@ -1410,8 +1353,8 @@ peek_real_address_q:
           r2(out) : result quadword
 
           This is provided as a cheapskate way of manipulating device
-          registers for debugging (to avoid the need to onchip_remap the debug
-          module, and to avoid the need to onchip_remap the watchpoint
+          registers for debugging (to avoid the need to ioremap the debug
+          module, and to avoid the need to ioremap the watchpoint
           controller in a way that identity maps sufficient bits to avoid the
           SH5-101 cut2 silicon defect).
 
@@ -1459,8 +1402,8 @@ poke_real_address_q:
           r3 : quadword value to write.
 
           This is provided as a cheapskate way of manipulating device
-          registers for debugging (to avoid the need to onchip_remap the debug
-          module, and to avoid the need to onchip_remap the watchpoint
+          registers for debugging (to avoid the need to ioremap the debug
+          module, and to avoid the need to ioremap the watchpoint
           controller in a way that identity maps sufficient bits to avoid the
           SH5-101 cut2 silicon defect).
 
diff --git a/arch/sh/kernel/cpu/sh5/setup-sh5.c b/arch/sh/kernel/cpu/sh5/setup-sh5.c
new file mode 100644 (file)
index 0000000..f5ff1ac
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * SH5-101/SH5-103 CPU Setup
+ *
+ *  Copyright (C) 2009  Paul Mundt
+ *
+ * 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.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/serial_sci.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/sh_timer.h>
+#include <asm/addrspace.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+       {
+               .mapbase        = PHYS_PERIPHERAL_BLOCK + 0x01030000,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+               .type           = PORT_SCIF,
+               .irqs           = { 39, 40, 42, 0 },
+       }, {
+               .flags = 0,
+       }
+};
+
+static struct platform_device sci_device = {
+       .name           = "sh-sci",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = sci_platform_data,
+       },
+};
+
+static struct resource rtc_resources[] = {
+       [0] = {
+               .start  = PHYS_PERIPHERAL_BLOCK + 0x01040000,
+               .end    = PHYS_PERIPHERAL_BLOCK + 0x01040000 + 0x58 - 1,
+               .flags  = IORESOURCE_IO,
+       },
+       [1] = {
+               /* Period IRQ */
+               .start  = IRQ_PRI,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               /* Carry IRQ */
+               .start  = IRQ_CUI,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               /* Alarm IRQ */
+               .start  = IRQ_ATI,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device rtc_device = {
+       .name           = "sh-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(rtc_resources),
+       .resource       = rtc_resources,
+};
+
+#define        TMU_BLOCK_OFF   0x01020000
+#define TMU_BASE       PHYS_PERIPHERAL_BLOCK + TMU_BLOCK_OFF
+#define TMU0_BASE      (TMU_BASE + 0x8 + (0xc * 0x0))
+#define TMU1_BASE      (TMU_BASE + 0x8 + (0xc * 0x1))
+#define TMU2_BASE      (TMU_BASE + 0x8 + (0xc * 0x2))
+
+static struct sh_timer_config tmu0_platform_data = {
+       .name = "TMU0",
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clk = "peripheral_clk",
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .name   = "TMU0",
+               .start  = TMU0_BASE,
+               .end    = TMU0_BASE + 0xc - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_TUNI0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .name = "TMU1",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clk = "peripheral_clk",
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .name   = "TMU1",
+               .start  = TMU1_BASE,
+               .end    = TMU1_BASE + 0xc - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_TUNI1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .name = "TMU2",
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+       .clk = "peripheral_clk",
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .name   = "TMU2",
+               .start  = TMU2_BASE,
+               .end    = TMU2_BASE + 0xc - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_TUNI2,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
+static struct platform_device *sh5_early_devices[] __initdata = {
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+};
+
+static struct platform_device *sh5_devices[] __initdata = {
+       &sci_device,
+       &rtc_device,
+};
+
+static int __init sh5_devices_setup(void)
+{
+       int ret;
+
+       ret = platform_add_devices(sh5_early_devices,
+                                  ARRAY_SIZE(sh5_early_devices));
+       if (unlikely(ret != 0))
+               return ret;
+
+       return platform_add_devices(sh5_devices,
+                                   ARRAY_SIZE(sh5_devices));
+}
+__initcall(sh5_devices_setup);
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh5_early_devices,
+                                  ARRAY_SIZE(sh5_early_devices));
+}
index 29cf4588fc050a996d2e62f95aa4f3ada2ad9733..4f85fffaa557126dffb78ea2baf67de591aa5c2b 100644 (file)
@@ -12,6 +12,7 @@
  * for more details.
  */
 #include <linux/module.h>
+#include <linux/pci.h>
 #include <asm/machvec.h>
 #include <asm/io.h>
 
index c22853b059efd118528cbff82a02b399412add8c..77dfecb643739d5e6abd8ec153289c1ba90a4d6a 100644 (file)
@@ -267,7 +267,7 @@ static struct mem_access trapped_io_access = {
 int handle_trapped_io(struct pt_regs *regs, unsigned long address)
 {
        mm_segment_t oldfs;
-       opcode_t instruction;
+       insn_size_t instruction;
        int tmp;
 
        if (!lookup_tiop(address))
index 3f1372eb0091f69ab93fb0912a3162c143d164f5..3d09062f4682718b43ec607649ca466ddcc6f670 100644 (file)
@@ -31,39 +31,64 @@ void ack_bad_irq(unsigned int irq)
 }
 
 #if defined(CONFIG_PROC_FS)
+/*
+ * /proc/interrupts printing:
+ */
+static int show_other_interrupts(struct seq_file *p, int prec)
+{
+       seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
+       return 0;
+}
+
 int show_interrupts(struct seq_file *p, void *v)
 {
-       int i = *(loff_t *) v, j;
-       struct irqaction * action;
-       unsigned long flags;
+       unsigned long flags, any_count = 0;
+       int i = *(loff_t *)v, j, prec;
+       struct irqaction *action;
+       struct irq_desc *desc;
+
+       if (i > nr_irqs)
+               return 0;
+
+       for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec)
+               j *= 10;
+
+       if (i == nr_irqs)
+               return show_other_interrupts(p, prec);
 
        if (i == 0) {
-               seq_puts(p, "           ");
+               seq_printf(p, "%*s", prec + 8, "");
                for_each_online_cpu(j)
-                       seq_printf(p, "CPU%d       ",j);
+                       seq_printf(p, "CPU%-8d", j);
                seq_putc(p, '\n');
        }
 
-       if (i < sh_mv.mv_nr_irqs) {
-               spin_lock_irqsave(&irq_desc[i].lock, flags);
-               action = irq_desc[i].action;
-               if (!action)
-                       goto unlock;
-               seq_printf(p, "%3d: ",i);
-               for_each_online_cpu(j)
-                       seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-               seq_printf(p, " %14s", irq_desc[i].chip->name);
-               seq_printf(p, "-%-8s", irq_desc[i].name);
-               seq_printf(p, "  %s", action->name);
+       desc = irq_to_desc(i);
+       if (!desc)
+               return 0;
+
+       spin_lock_irqsave(&desc->lock, flags);
+       for_each_online_cpu(j)
+               any_count |= kstat_irqs_cpu(i, j);
+       action = desc->action;
+       if (!action && !any_count)
+               goto out;
+
+       seq_printf(p, "%*d: ", prec, i);
+       for_each_online_cpu(j)
+               seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
+       seq_printf(p, " %14s", desc->chip->name);
+       seq_printf(p, "-%-8s", desc->name);
 
-               for (action=action->next; action; action = action->next)
+       if (action) {
+               seq_printf(p, "  %s", action->name);
+               while ((action = action->next) != NULL)
                        seq_printf(p, ", %s", action->name);
-               seq_putc(p, '\n');
-unlock:
-               spin_unlock_irqrestore(&irq_desc[i].lock, flags);
-       } else if (i == sh_mv.mv_nr_irqs)
-               seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count));
+       }
 
+       seq_putc(p, '\n');
+out:
+       spin_unlock_irqrestore(&desc->lock, flags);
        return 0;
 }
 #endif
@@ -254,3 +279,11 @@ void __init init_IRQ(void)
 
        irq_ctx_init(smp_processor_id());
 }
+
+#ifdef CONFIG_SPARSE_IRQ
+int __init arch_probe_nr_irqs(void)
+{
+       nr_irqs = sh_mv.mv_nr_irqs;
+       return 0;
+}
+#endif
index 7c747e7d71b86c35b2fe5eb58b17160a4e563931..305aad742aec8aba7d9ce65d235f7ccaddca6bfa 100644 (file)
@@ -47,7 +47,7 @@ char in_nmi = 0;      /* Set during NMI to prevent re-entry */
 /* Calculate the new address for after a step */
 static short *get_step_address(struct pt_regs *linux_regs)
 {
-       opcode_t op = __raw_readw(linux_regs->pc);
+       insn_size_t op = __raw_readw(linux_regs->pc);
        long addr;
 
        /* BT */
@@ -134,7 +134,7 @@ static short *get_step_address(struct pt_regs *linux_regs)
  */
 
 static unsigned long stepped_address;
-static opcode_t stepped_opcode;
+static insn_size_t stepped_opcode;
 
 static void do_single_step(struct pt_regs *linux_regs)
 {
index c1ea41e5812a5897a5abfc8e8bb94fba925e414d..548f6607fd0fbd074c8ee23759cc6710015618a8 100644 (file)
@@ -129,6 +129,7 @@ void __init sh_mv_setup(void)
        mv_set(ioport_map);
        mv_set(ioport_unmap);
        mv_set(irq_demux);
+       mv_set(mode_pins);
 
        if (!sh_mv.mv_nr_irqs)
                sh_mv.mv_nr_irqs = NR_IRQS;
index c43081039dd571ab3992628830d5cd171a3d23fd..c19b0f7d2cc13a100aaeecd24b420eeaff30c32f 100644 (file)
@@ -90,7 +90,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
                 * SHmedia, the LSB of the symbol needs to be asserted
                 * for the CPU to be in SHmedia mode when it starts executing
                 * the branch target. */
-               relocation |= (sym->st_other & 4);
+               relocation |= !!(sym->st_other & 4);
 #endif
 
                switch (ELF32_R_TYPE(rel[i].r_info)) {
index 6d94725d22f24d3344dfa79ad602674e46cab440..9289ede29c7b405fa02dc2b71ebf655d1def9ef0 100644 (file)
@@ -251,7 +251,8 @@ static void ubc_set_tracing(int asid, unsigned long pc)
 
        if (current_cpu_data.type == CPU_SH7729 ||
            current_cpu_data.type == CPU_SH7710 ||
-           current_cpu_data.type == CPU_SH7712) {
+           current_cpu_data.type == CPU_SH7712 ||
+           current_cpu_data.type == CPU_SH7203){
                ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
                ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
        } else {
@@ -407,6 +408,7 @@ asmlinkage void break_point_trap(void)
 #else
        ctrl_outw(0, UBC_BBRA);
        ctrl_outw(0, UBC_BBRB);
+       ctrl_outl(0, UBC_BRCR);
 #endif
        current->thread.ubc_pc = 0;
        ubc_usercnt -= 1;
index f7b22dd83b0c125ada90571539eda06530d04613..3392e835a374af8895fe8330444854117ebea7a3 100644 (file)
@@ -334,6 +334,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                        [(addr - (long)&dummy->fpu) >> 2];
                } else if (addr == (long) &dummy->u_fpvalid)
                        tmp = !!tsk_used_math(child);
+               else if (addr == PT_TEXT_ADDR)
+                       tmp = child->mm->start_code;
+               else if (addr == PT_DATA_ADDR)
+                       tmp = child->mm->start_data;
+               else if (addr == PT_TEXT_END_ADDR)
+                       tmp = child->mm->end_code;
+               else if (addr == PT_TEXT_LEN)
+                       tmp = child->mm->end_code - child->mm->start_code;
                else
                        tmp = 0;
                ret = put_user(tmp, datap);
index 04a6004fccc45d39d25087ebd00c29025f0f824f..dd38338553ef5484306907ae7465e36f93afa7c6 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mmzone.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/platform_device.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/page.h>
@@ -155,7 +156,7 @@ static void __init reserve_crashkernel(void)
                        &crash_size, &crash_base);
        if (ret == 0 && crash_size) {
                if (crash_base <= 0) {
-                       vp = alloc_bootmem_nopanic(crash_size); 
+                       vp = alloc_bootmem_nopanic(crash_size);
                        if (!vp) {
                                printk(KERN_INFO "crashkernel allocation "
                                       "failed\n");
@@ -184,7 +185,6 @@ static inline void __init reserve_crashkernel(void)
 {}
 #endif
 
-#ifndef CONFIG_GENERIC_CALIBRATE_DELAY
 void __cpuinit calibrate_delay(void)
 {
        struct clk *clk = clk_get(NULL, "cpu_clk");
@@ -200,7 +200,6 @@ void __cpuinit calibrate_delay(void)
                         (loops_per_jiffy/(5000/HZ)) % 100,
                         loops_per_jiffy);
 }
-#endif
 
 void __init __add_active_range(unsigned int nid, unsigned long start_pfn,
                                                unsigned long end_pfn)
@@ -328,6 +327,10 @@ static int __init parse_elfcorehdr(char *arg)
 early_param("elfcorehdr", parse_elfcorehdr);
 #endif
 
+void __init __attribute__ ((weak)) plat_early_device_setup(void)
+{
+}
+
 void __init setup_arch(char **cmdline_p)
 {
        enable_mmu();
@@ -381,6 +384,8 @@ void __init setup_arch(char **cmdline_p)
 
        parse_early_param();
 
+       plat_early_device_setup();
+
        sh_mv_setup();
 
        /*
@@ -415,6 +420,18 @@ void __init setup_arch(char **cmdline_p)
 #endif
 }
 
+/* processor boot mode configuration */
+int generic_mode_pins(void)
+{
+       pr_warning("generic_mode_pins(): missing mode pin configuration\n");
+       return 0;
+}
+
+int test_mode_pin(int pin)
+{
+       return sh_mv.mv_mode_pins() & pin;
+}
+
 static const char *cpu_name[] = {
        [CPU_SH7201]    = "SH7201",
        [CPU_SH7203]    = "SH7203",     [CPU_SH7263]    = "SH7263",
@@ -435,7 +452,8 @@ static const char *cpu_name[] = {
        [CPU_SH7722]    = "SH7722",     [CPU_SHX3]      = "SH-X3",
        [CPU_SH5_101]   = "SH5-101",    [CPU_SH5_103]   = "SH5-103",
        [CPU_MXG]       = "MX-G",       [CPU_SH7723]    = "SH7723",
-       [CPU_SH7366]    = "SH7366",     [CPU_SH_NONE]   = "Unknown"
+       [CPU_SH7366]    = "SH7366",     [CPU_SH7724]    = "SH7724",
+       [CPU_SH_NONE]   = "Unknown"
 };
 
 const char *get_cpu_subtype(struct sh_cpuinfo *c)
index 528de2955c814dcc4286fd83011439635535f766..fcc5de31f83b81a6a1305bae666623b0e212e34e 100644 (file)
 #include <asm/ftrace.h>
 
 extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-extern struct hw_interrupt_type no_irq_type;
 
 /* platform dependent support */
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(irq_desc);
-EXPORT_SYMBOL(no_irq_type);
-
 EXPORT_SYMBOL(strlen);
 
 /* PCI exports */
@@ -41,11 +37,6 @@ EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(__copy_user);
-
-#ifdef CONFIG_MMU
-EXPORT_SYMBOL(get_vm_area);
-#endif
-
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(__ndelay);
 EXPORT_SYMBOL(__const_udelay);
index 0d74d6b8774e422b1895b7ec1e3b0feb3b4c427e..8f54ef0cfbcaa5648be466725b33ec1361639c66 100644 (file)
@@ -76,5 +76,7 @@ EXPORT_SYMBOL(strcpy);
 #define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
 
 DECLARE_EXPORT(__sdivsi3);
+DECLARE_EXPORT(__sdivsi3_1);
+DECLARE_EXPORT(__sdivsi3_2);
 DECLARE_EXPORT(__udivsi3);
 DECLARE_EXPORT(__div_table);
index 05202edd8e212a2a9fbfecdb0dd09024ce313389..a9fff9f731ec11c4273592f6ab932d351c7716d6 100644 (file)
@@ -350,4 +350,5 @@ ENTRY(sys_call_table)
        .long sys_pipe2
        .long sys_inotify_init1
        .long sys_preadv
-       .long sys_writev
+       .long sys_pwritev
+       .long sys_rt_tgsigqueueinfo     /* 335 */
index a083609f92847ab9e602eac9b2940bd60437292f..75c1889af1ed53c725491e8bf35cb3ed00cb382a 100644 (file)
@@ -389,3 +389,4 @@ sys_call_table:
        .long sys_inotify_init1         /* 360 */
        .long sys_preadv
        .long sys_pwritev
+       .long sys_rt_tgsigqueueinfo
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
new file mode 100644 (file)
index 0000000..2edde32
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ *  arch/sh/kernel/time.c
+ *
+ *  Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
+ *  Copyright (C) 2000  Philipp Rumpf <prumpf@tux.org>
+ *  Copyright (C) 2002 - 2009  Paul Mundt
+ *  Copyright (C) 2002  M. R. Brown  <mrbrown@linux-sh.org>
+ *
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/profile.h>
+#include <linux/timex.h>
+#include <linux/sched.h>
+#include <linux/clockchips.h>
+#include <linux/platform_device.h>
+#include <linux/smp.h>
+#include <linux/rtc.h>
+#include <asm/clock.h>
+#include <asm/rtc.h>
+
+/* Dummy RTC ops */
+static void null_rtc_get_time(struct timespec *tv)
+{
+       tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0);
+       tv->tv_nsec = 0;
+}
+
+static int null_rtc_set_time(const time_t secs)
+{
+       return 0;
+}
+
+void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
+int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
+
+#ifdef CONFIG_GENERIC_CMOS_UPDATE
+unsigned long read_persistent_clock(void)
+{
+       struct timespec tv;
+       rtc_sh_get_time(&tv);
+       return tv.tv_sec;
+}
+
+int update_persistent_clock(struct timespec now)
+{
+       return rtc_sh_set_time(now.tv_sec);
+}
+#endif
+
+unsigned int get_rtc_time(struct rtc_time *tm)
+{
+       if (rtc_sh_get_time != null_rtc_get_time) {
+               struct timespec tv;
+
+               rtc_sh_get_time(&tv);
+               rtc_time_to_tm(tv.tv_sec, tm);
+       }
+
+       return RTC_24H;
+}
+EXPORT_SYMBOL(get_rtc_time);
+
+int set_rtc_time(struct rtc_time *tm)
+{
+       unsigned long secs;
+
+       rtc_tm_to_time(tm, &secs);
+       return rtc_sh_set_time(secs);
+}
+EXPORT_SYMBOL(set_rtc_time);
+
+static int __init rtc_generic_init(void)
+{
+       struct platform_device *pdev;
+
+       if (rtc_sh_get_time == null_rtc_get_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_generic_init);
+
+void (*board_time_init)(void);
+
+unsigned long long sched_clock(void)
+{
+       return (jiffies_64 - INITIAL_JIFFIES) * (NSEC_PER_SEC / HZ);
+}
+
+static void __init sh_late_time_init(void)
+{
+       /*
+        * Make sure all compiled-in early timers register themselves.
+        * Run probe() for one "earlytimer" device.
+        */
+       early_platform_driver_register_all("earlytimer");
+       early_platform_driver_probe("earlytimer", 1, 0);
+}
+
+void __init time_init(void)
+{
+       if (board_time_init)
+               board_time_init();
+
+       clk_init();
+
+       rtc_sh_get_time(&xtime);
+       set_normalized_timespec(&wall_to_monotonic,
+                               -xtime.tv_sec, -xtime.tv_nsec);
+
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+       local_timer_setup(smp_processor_id());
+#endif
+
+       late_time_init = sh_late_time_init;
+}
diff --git a/arch/sh/kernel/time_32.c b/arch/sh/kernel/time_32.c
deleted file mode 100644 (file)
index 1700d24..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- *  arch/sh/kernel/time_32.c
- *
- *  Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
- *  Copyright (C) 2000  Philipp Rumpf <prumpf@tux.org>
- *  Copyright (C) 2002 - 2008  Paul Mundt
- *  Copyright (C) 2002  M. R. Brown  <mrbrown@linux-sh.org>
- *
- *  Some code taken from i386 version.
- *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/profile.h>
-#include <linux/timex.h>
-#include <linux/sched.h>
-#include <linux/clockchips.h>
-#include <linux/mc146818rtc.h> /* for rtc_lock */
-#include <linux/smp.h>
-#include <asm/clock.h>
-#include <asm/rtc.h>
-#include <asm/timer.h>
-#include <asm/kgdb.h>
-
-struct sys_timer *sys_timer;
-
-/* Move this somewhere more sensible.. */
-DEFINE_SPINLOCK(rtc_lock);
-EXPORT_SYMBOL(rtc_lock);
-
-/* Dummy RTC ops */
-static void null_rtc_get_time(struct timespec *tv)
-{
-       tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0);
-       tv->tv_nsec = 0;
-}
-
-static int null_rtc_set_time(const time_t secs)
-{
-       return 0;
-}
-
-void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
-int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
-
-#ifndef CONFIG_GENERIC_TIME
-void do_gettimeofday(struct timeval *tv)
-{
-       unsigned long flags;
-       unsigned long seq;
-       unsigned long usec, sec;
-
-       do {
-               /*
-                * Turn off IRQs when grabbing xtime_lock, so that
-                * the sys_timer get_offset code doesn't have to handle it.
-                */
-               seq = read_seqbegin_irqsave(&xtime_lock, flags);
-               usec = get_timer_offset();
-               sec = xtime.tv_sec;
-               usec += xtime.tv_nsec / NSEC_PER_USEC;
-       } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-
-       while (usec >= 1000000) {
-               usec -= 1000000;
-               sec++;
-       }
-
-       tv->tv_sec = sec;
-       tv->tv_usec = usec;
-}
-EXPORT_SYMBOL(do_gettimeofday);
-
-int do_settimeofday(struct timespec *tv)
-{
-       time_t wtm_sec, sec = tv->tv_sec;
-       long wtm_nsec, nsec = tv->tv_nsec;
-
-       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!
-        */
-       nsec -= get_timer_offset() * NSEC_PER_USEC;
-
-       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);
-       clock_was_set();
-
-       return 0;
-}
-EXPORT_SYMBOL(do_settimeofday);
-#endif /* !CONFIG_GENERIC_TIME */
-
-/* last time the RTC clock got updated */
-static long last_rtc_update;
-
-/*
- * handle_timer_tick() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
- */
-void handle_timer_tick(void)
-{
-       if (current->pid)
-               profile_tick(CPU_PROFILING);
-
-       /*
-        * Here we are in the timer irq handler. We just have irqs locally
-        * disabled but we don't know if the timer_bh is running on the other
-        * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
-        * the irq version of write_lock because as just said we have irq
-        * locally disabled. -arca
-        */
-       write_seqlock(&xtime_lock);
-       do_timer(1);
-
-       /*
-        * If we have an externally synchronized Linux clock, then update
-        * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-        * called as close as possible to 500 ms before the new second starts.
-        */
-       if (ntp_synced() &&
-           xtime.tv_sec > last_rtc_update + 660 &&
-           (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
-           (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
-               if (rtc_sh_set_time(xtime.tv_sec) == 0)
-                       last_rtc_update = xtime.tv_sec;
-               else
-                       /* do it again in 60s */
-                       last_rtc_update = xtime.tv_sec - 600;
-       }
-       write_sequnlock(&xtime_lock);
-
-#ifndef CONFIG_SMP
-       update_process_times(user_mode(get_irq_regs()));
-#endif
-}
-
-#ifdef CONFIG_PM
-int timer_suspend(struct sys_device *dev, pm_message_t state)
-{
-       struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
-
-       sys_timer->ops->stop();
-
-       return 0;
-}
-
-int timer_resume(struct sys_device *dev)
-{
-       struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
-
-       sys_timer->ops->start();
-
-       return 0;
-}
-#else
-#define timer_suspend NULL
-#define timer_resume NULL
-#endif
-
-static struct sysdev_class timer_sysclass = {
-       .name    = "timer",
-       .suspend = timer_suspend,
-       .resume  = timer_resume,
-};
-
-static int __init timer_init_sysfs(void)
-{
-       int ret;
-
-       if (!sys_timer)
-               return 0;
-
-       ret = sysdev_class_register(&timer_sysclass);
-       if (ret != 0)
-               return ret;
-
-       sys_timer->dev.cls = &timer_sysclass;
-       return sysdev_register(&sys_timer->dev);
-}
-device_initcall(timer_init_sysfs);
-
-void (*board_time_init)(void);
-
-struct clocksource clocksource_sh = {
-       .name           = "SuperH",
-};
-
-#ifdef CONFIG_GENERIC_TIME
-unsigned long long sched_clock(void)
-{
-       unsigned long long cycles;
-
-       /* jiffies based sched_clock if no clocksource is installed */
-       if (!clocksource_sh.rating)
-               return (unsigned long long)jiffies * (NSEC_PER_SEC / HZ);
-
-       cycles = clocksource_sh.read(&clocksource_sh);
-       return cyc2ns(&clocksource_sh, cycles);
-}
-#endif
-
-void __init time_init(void)
-{
-       if (board_time_init)
-               board_time_init();
-
-       clk_init();
-
-       rtc_sh_get_time(&xtime);
-       set_normalized_timespec(&wall_to_monotonic,
-                               -xtime.tv_sec, -xtime.tv_nsec);
-
-#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
-       local_timer_setup(smp_processor_id());
-#endif
-
-       /*
-        * Find the timer to use as the system timer, it will be
-        * initialized for us.
-        */
-       sys_timer = get_sys_timer();
-       if (unlikely(!sys_timer))
-               panic("System timer missing.\n");
-
-       printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
-}
diff --git a/arch/sh/kernel/time_64.c b/arch/sh/kernel/time_64.c
deleted file mode 100644 (file)
index 988c77c..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * arch/sh/kernel/time_64.c
- *
- * Copyright (C) 2000, 2001  Paolo Alberelli
- * Copyright (C) 2003 - 2007  Paul Mundt
- * Copyright (C) 2003  Richard Curnow
- *
- *    Original TMU/RTC code taken from sh version.
- *    Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
- *      Some code taken from i386 version.
- *      Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *
- * 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.
- */
-#include <linux/errno.h>
-#include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/profile.h>
-#include <linux/smp.h>
-#include <linux/module.h>
-#include <linux/bcd.h>
-#include <linux/timex.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <cpu/registers.h>      /* required by inline __asm__ stmt. */
-#include <cpu/irq.h>
-#include <asm/addrspace.h>
-#include <asm/processor.h>
-#include <asm/uaccess.h>
-#include <asm/delay.h>
-#include <asm/clock.h>
-
-#define TMU_TOCR_INIT  0x00
-#define TMU0_TCR_INIT  0x0020
-#define TMU_TSTR_INIT  1
-#define TMU_TSTR_OFF   0
-
-/* Real Time Clock */
-#define        RTC_BLOCK_OFF   0x01040000
-#define RTC_BASE       PHYS_PERIPHERAL_BLOCK + RTC_BLOCK_OFF
-#define RTC_RCR1_CIE   0x10    /* Carry Interrupt Enable */
-#define RTC_RCR1       (rtc_base + 0x38)
-
-/* Time Management Unit */
-#define        TMU_BLOCK_OFF   0x01020000
-#define TMU_BASE       PHYS_PERIPHERAL_BLOCK + TMU_BLOCK_OFF
-#define TMU0_BASE      tmu_base + 0x8 + (0xc * 0x0)
-#define TMU1_BASE      tmu_base + 0x8 + (0xc * 0x1)
-#define TMU2_BASE      tmu_base + 0x8 + (0xc * 0x2)
-
-#define TMU_TOCR       tmu_base+0x0    /* Byte access */
-#define TMU_TSTR       tmu_base+0x4    /* Byte access */
-
-#define TMU0_TCOR      TMU0_BASE+0x0   /* Long access */
-#define TMU0_TCNT      TMU0_BASE+0x4   /* Long access */
-#define TMU0_TCR       TMU0_BASE+0x8   /* Word access */
-
-#define TICK_SIZE (tick_nsec / 1000)
-
-static unsigned long tmu_base, rtc_base;
-unsigned long cprc_base;
-
-/* Variables to allow interpolation of time of day to resolution better than a
- * jiffy. */
-
-/* This is effectively protected by xtime_lock */
-static unsigned long ctc_last_interrupt;
-static unsigned long long usecs_per_jiffy = 1000000/HZ; /* Approximation */
-
-#define CTC_JIFFY_SCALE_SHIFT 40
-
-/* 2**CTC_JIFFY_SCALE_SHIFT / ctc_ticks_per_jiffy */
-static unsigned long long scaled_recip_ctc_ticks_per_jiffy;
-
-/* Estimate number of microseconds that have elapsed since the last timer tick,
-   by scaling the delta that has occurred in the CTC register.
-
-   WARNING WARNING WARNING : This algorithm relies on the CTC decrementing at
-   the CPU clock rate.  If the CPU sleeps, the CTC stops counting.  Bear this
-   in mind if enabling SLEEP_WORKS in process.c.  In that case, this algorithm
-   probably needs to use TMU.TCNT0 instead.  This will work even if the CPU is
-   sleeping, though will be coarser.
-
-   FIXME : What if usecs_per_tick is moving around too much, e.g. if an adjtime
-   is running or if the freq or tick arguments of adjtimex are modified after
-   we have calibrated the scaling factor?  This will result in either a jump at
-   the end of a tick period, or a wrap backwards at the start of the next one,
-   if the application is reading the time of day often enough.  I think we
-   ought to do better than this.  For this reason, usecs_per_jiffy is left
-   separated out in the calculation below.  This allows some future hook into
-   the adjtime-related stuff in kernel/timer.c to remove this hazard.
-
-*/
-
-static unsigned long usecs_since_tick(void)
-{
-       unsigned long long current_ctc;
-       long ctc_ticks_since_interrupt;
-       unsigned long long ull_ctc_ticks_since_interrupt;
-       unsigned long result;
-
-       unsigned long long mul1_out;
-       unsigned long long mul1_out_high;
-       unsigned long long mul2_out_low, mul2_out_high;
-
-       /* Read CTC register */
-       asm ("getcon cr62, %0" : "=r" (current_ctc));
-       /* Note, the CTC counts down on each CPU clock, not up.
-          Note(2), use long type to get correct wraparound arithmetic when
-          the counter crosses zero. */
-       ctc_ticks_since_interrupt = (long) ctc_last_interrupt - (long) current_ctc;
-       ull_ctc_ticks_since_interrupt = (unsigned long long) ctc_ticks_since_interrupt;
-
-       /* Inline assembly to do 32x32x32->64 multiplier */
-       asm volatile ("mulu.l %1, %2, %0" :
-            "=r" (mul1_out) :
-            "r" (ull_ctc_ticks_since_interrupt), "r" (usecs_per_jiffy));
-
-       mul1_out_high = mul1_out >> 32;
-
-       asm volatile ("mulu.l %1, %2, %0" :
-            "=r" (mul2_out_low) :
-            "r" (mul1_out), "r" (scaled_recip_ctc_ticks_per_jiffy));
-
-#if 1
-       asm volatile ("mulu.l %1, %2, %0" :
-            "=r" (mul2_out_high) :
-            "r" (mul1_out_high), "r" (scaled_recip_ctc_ticks_per_jiffy));
-#endif
-
-       result = (unsigned long) (((mul2_out_high << 32) + mul2_out_low) >> CTC_JIFFY_SCALE_SHIFT);
-
-       return result;
-}
-
-void do_gettimeofday(struct timeval *tv)
-{
-       unsigned long flags;
-       unsigned long seq;
-       unsigned long usec, sec;
-
-       do {
-               seq = read_seqbegin_irqsave(&xtime_lock, flags);
-               usec = usecs_since_tick();
-               sec = xtime.tv_sec;
-               usec += xtime.tv_nsec / 1000;
-       } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-
-       while (usec >= 1000000) {
-               usec -= 1000000;
-               sec++;
-       }
-
-       tv->tv_sec = sec;
-       tv->tv_usec = usec;
-}
-EXPORT_SYMBOL(do_gettimeofday);
-
-int do_settimeofday(struct timespec *tv)
-{
-       time_t wtm_sec, sec = tv->tv_sec;
-       long wtm_nsec, nsec = tv->tv_nsec;
-
-       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!
-        */
-       nsec -= 1000 * usecs_since_tick();
-
-       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);
-       clock_was_set();
-
-       return 0;
-}
-EXPORT_SYMBOL(do_settimeofday);
-
-/* Dummy RTC ops */
-static void null_rtc_get_time(struct timespec *tv)
-{
-       tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0);
-       tv->tv_nsec = 0;
-}
-
-static int null_rtc_set_time(const time_t secs)
-{
-       return 0;
-}
-
-void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
-int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
-
-/* last time the RTC clock got updated */
-static long last_rtc_update;
-
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
- */
-static inline void do_timer_interrupt(void)
-{
-       unsigned long long current_ctc;
-
-       if (current->pid)
-               profile_tick(CPU_PROFILING);
-
-       /*
-        * Here we are in the timer irq handler. We just have irqs locally
-        * disabled but we don't know if the timer_bh is running on the other
-        * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
-        * the irq version of write_lock because as just said we have irq
-        * locally disabled. -arca
-        */
-       write_seqlock(&xtime_lock);
-       asm ("getcon cr62, %0" : "=r" (current_ctc));
-       ctc_last_interrupt = (unsigned long) current_ctc;
-
-       do_timer(1);
-
-       /*
-        * If we have an externally synchronized Linux clock, then update
-        * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-        * called as close as possible to 500 ms before the new second starts.
-        */
-       if (ntp_synced() &&
-           xtime.tv_sec > last_rtc_update + 660 &&
-           (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
-           (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
-               if (rtc_sh_set_time(xtime.tv_sec) == 0)
-                       last_rtc_update = xtime.tv_sec;
-               else
-                       /* do it again in 60 s */
-                       last_rtc_update = xtime.tv_sec - 600;
-       }
-       write_sequnlock(&xtime_lock);
-
-#ifndef CONFIG_SMP
-       update_process_times(user_mode(get_irq_regs()));
-#endif
-}
-
-/*
- * This is the same as the above, except we _also_ save the current
- * Time Stamp Counter value at the time of the timer interrupt, so that
- * we later on can estimate the time of day more exactly.
- */
-static irqreturn_t timer_interrupt(int irq, void *dev_id)
-{
-       unsigned long timer_status;
-
-       /* Clear UNF bit */
-       timer_status = ctrl_inw(TMU0_TCR);
-       timer_status &= ~0x100;
-       ctrl_outw(timer_status, TMU0_TCR);
-
-       do_timer_interrupt();
-
-       return IRQ_HANDLED;
-}
-
-static struct irqaction irq0  = {
-       .handler = timer_interrupt,
-       .flags = IRQF_DISABLED,
-       .name = "timer",
-};
-
-void __init time_init(void)
-{
-       unsigned long interval;
-       struct clk *clk;
-
-       tmu_base = onchip_remap(TMU_BASE, 1024, "TMU");
-       if (!tmu_base) {
-               panic("Unable to remap TMU\n");
-       }
-
-       rtc_base = onchip_remap(RTC_BASE, 1024, "RTC");
-       if (!rtc_base) {
-               panic("Unable to remap RTC\n");
-       }
-
-       clk = clk_get(NULL, "cpu_clk");
-       scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) /
-                       (unsigned long long)(clk_get_rate(clk) / HZ));
-
-       rtc_sh_get_time(&xtime);
-
-       setup_irq(TIMER_IRQ, &irq0);
-
-       clk = clk_get(NULL, "module_clk");
-       interval = (clk_get_rate(clk)/(HZ*4));
-
-       printk("Interval = %ld\n", interval);
-
-       /* Start TMU0 */
-       ctrl_outb(TMU_TSTR_OFF, TMU_TSTR);
-       ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
-       ctrl_outw(TMU0_TCR_INIT, TMU0_TCR);
-       ctrl_outl(interval, TMU0_TCOR);
-       ctrl_outl(interval, TMU0_TCNT);
-       ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
-}
-
-static struct resource rtc_resources[] = {
-       [0] = {
-               /* RTC base, filled in by rtc_init */
-               .flags  = IORESOURCE_IO,
-       },
-       [1] = {
-               /* Period IRQ */
-               .start  = IRQ_PRI,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               /* Carry IRQ */
-               .start  = IRQ_CUI,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               /* Alarm IRQ */
-               .start  = IRQ_ATI,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device rtc_device = {
-       .name           = "sh-rtc",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(rtc_resources),
-       .resource       = rtc_resources,
-};
-
-static int __init rtc_init(void)
-{
-       rtc_resources[0].start  = rtc_base;
-       rtc_resources[0].end    = rtc_resources[0].start + 0x58 - 1;
-
-       return platform_device_register(&rtc_device);
-}
-device_initcall(rtc_init);
diff --git a/arch/sh/kernel/timers/Makefile b/arch/sh/kernel/timers/Makefile
deleted file mode 100644 (file)
index 0b7f857..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for the various Linux/SuperH timers
-#
-
-obj-y  := timer.o
-
-obj-$(CONFIG_SH_TMU)           += timer-tmu.o
-obj-$(CONFIG_SH_MTU2)          += timer-mtu2.o
-obj-$(CONFIG_SH_CMT)           += timer-cmt.o
-
-obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)    += timer-broadcast.o
diff --git a/arch/sh/kernel/timers/timer-cmt.c b/arch/sh/kernel/timers/timer-cmt.c
deleted file mode 100644 (file)
index 9aa3486..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * arch/sh/kernel/timers/timer-cmt.c - CMT Timer Support
- *
- *  Copyright (C) 2005  Yoshinori Sato
- *
- * 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.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/seqlock.h>
-#include <asm/timer.h>
-#include <asm/rtc.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/clock.h>
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7619)
-#define CMT_CMSTR      0xf84a0070
-#define CMT_CMCSR_0    0xf84a0072
-#define CMT_CMCNT_0    0xf84a0074
-#define CMT_CMCOR_0    0xf84a0076
-#define CMT_CMCSR_1    0xf84a0078
-#define CMT_CMCNT_1    0xf84a007a
-#define CMT_CMCOR_1    0xf84a007c
-
-#define STBCR3         0xf80a0000
-#define cmt_clock_enable() do {        ctrl_outb(ctrl_inb(STBCR3) & ~0x10, STBCR3); } while(0)
-#define CMT_CMCSR_INIT 0x0040
-#define CMT_CMCSR_CALIB        0x0000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7206) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7263)
-#define CMT_CMSTR      0xfffec000
-#define CMT_CMCSR_0    0xfffec002
-#define CMT_CMCNT_0    0xfffec004
-#define CMT_CMCOR_0    0xfffec006
-
-#define STBCR4         0xfffe040c
-#define cmt_clock_enable() do {        ctrl_outb(ctrl_inb(STBCR4) & ~0x04, STBCR4); } while(0)
-#define CMT_CMCSR_INIT 0x0040
-#define CMT_CMCSR_CALIB        0x0000
-#else
-#error "Unknown CPU SUBTYPE"
-#endif
-
-static unsigned long cmt_timer_get_offset(void)
-{
-       int count;
-       static unsigned short count_p = 0xffff;    /* for the first call after boot */
-       static unsigned long jiffies_p = 0;
-
-       /*
-        * cache volatile jiffies temporarily; we have IRQs turned off.
-        */
-       unsigned long jiffies_t;
-
-       /* timer count may underflow right here */
-       count =  ctrl_inw(CMT_CMCOR_0);
-       count -= ctrl_inw(CMT_CMCNT_0);
-
-       jiffies_t = jiffies;
-
-       /*
-        * avoiding timer inconsistencies (they are rare, but they happen)...
-        * there is one kind of problem that must be avoided here:
-        *  1. the timer counter underflows
-        */
-
-       if (jiffies_t == jiffies_p) {
-               if (count > count_p) {
-                       /* the nutcase */
-                       if (ctrl_inw(CMT_CMCSR_0) & 0x80) { /* Check CMF bit */
-                               count -= LATCH;
-                       } else {
-                               printk("%s (): hardware timer problem?\n",
-                                      __func__);
-                       }
-               }
-       } else
-               jiffies_p = jiffies_t;
-
-       count_p = count;
-
-       count = ((LATCH-1) - count) * TICK_SIZE;
-       count = (count + LATCH/2) / LATCH;
-
-       return count;
-}
-
-static irqreturn_t cmt_timer_interrupt(int irq, void *dev_id)
-{
-       unsigned long timer_status;
-
-       /* Clear CMF bit */
-       timer_status = ctrl_inw(CMT_CMCSR_0);
-       timer_status &= ~0x80;
-       ctrl_outw(timer_status, CMT_CMCSR_0);
-
-       handle_timer_tick();
-
-       return IRQ_HANDLED;
-}
-
-static struct irqaction cmt_irq = {
-       .name           = "timer",
-       .handler        = cmt_timer_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-};
-
-static void cmt_clk_init(struct clk *clk)
-{
-       u8 divisor = CMT_CMCSR_INIT & 0x3;
-       ctrl_inw(CMT_CMCSR_0);
-       ctrl_outw(CMT_CMCSR_INIT, CMT_CMCSR_0);
-       clk->parent = clk_get(NULL, "module_clk");
-       clk->rate = clk->parent->rate / (8 << (divisor << 1));
-}
-
-static void cmt_clk_recalc(struct clk *clk)
-{
-       u8 divisor = ctrl_inw(CMT_CMCSR_0) & 0x3;
-       clk->rate = clk->parent->rate / (8 << (divisor << 1));
-}
-
-static struct clk_ops cmt_clk_ops = {
-       .init           = cmt_clk_init,
-       .recalc         = cmt_clk_recalc,
-};
-
-static struct clk cmt0_clk = {
-       .name           = "cmt0_clk",
-       .ops            = &cmt_clk_ops,
-};
-
-static int cmt_timer_start(void)
-{
-       ctrl_outw(ctrl_inw(CMT_CMSTR) | 0x01, CMT_CMSTR);
-       return 0;
-}
-
-static int cmt_timer_stop(void)
-{
-       ctrl_outw(ctrl_inw(CMT_CMSTR) & ~0x01, CMT_CMSTR);
-       return 0;
-}
-
-static int cmt_timer_init(void)
-{
-       unsigned long interval;
-
-       cmt_clock_enable();
-
-       setup_irq(CONFIG_SH_TIMER_IRQ, &cmt_irq);
-
-       cmt0_clk.parent = clk_get(NULL, "module_clk");
-
-       cmt_timer_stop();
-
-       interval = cmt0_clk.parent->rate / 8 / HZ;
-       printk(KERN_INFO "Interval = %ld\n", interval);
-
-       ctrl_outw(interval, CMT_CMCOR_0);
-
-       clk_register(&cmt0_clk);
-       clk_enable(&cmt0_clk);
-
-       cmt_timer_start();
-
-       return 0;
-}
-
-static struct sys_timer_ops cmt_timer_ops = {
-       .init           = cmt_timer_init,
-       .start          = cmt_timer_start,
-       .stop           = cmt_timer_stop,
-#ifndef CONFIG_GENERIC_TIME
-       .get_offset     = cmt_timer_get_offset,
-#endif
-};
-
-struct sys_timer cmt_timer = {
-       .name   = "cmt",
-       .ops    = &cmt_timer_ops,
-};
diff --git a/arch/sh/kernel/timers/timer-mtu2.c b/arch/sh/kernel/timers/timer-mtu2.c
deleted file mode 100644 (file)
index 9b0ef01..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * arch/sh/kernel/timers/timer-mtu2.c - MTU2 Timer Support
- *
- *  Copyright (C) 2005  Paul Mundt
- *
- * Based off of arch/sh/kernel/timers/timer-tmu.c
- *
- * 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.
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/seqlock.h>
-#include <asm/timer.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/clock.h>
-
-/*
- * We use channel 1 for our lowly system timer. Channel 2 would be the other
- * likely candidate, but we leave it alone as it has higher divisors that
- * would be of more use to other more interesting applications.
- *
- * TODO: Presently we only implement a 16-bit single-channel system timer.
- * However, we can implement channel cascade if we go the overflow route and
- * get away with using 2 MTU2 channels as a 32-bit timer.
- */
-#define MTU2_TSTR      0xfffe4280
-#define MTU2_TCR_1     0xfffe4380
-#define MTU2_TMDR_1    0xfffe4381
-#define MTU2_TIOR_1    0xfffe4382
-#define MTU2_TIER_1    0xfffe4384
-#define MTU2_TSR_1     0xfffe4385
-#define MTU2_TCNT_1    0xfffe4386      /* 16-bit counter */
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7201) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7203)
-#define MTU2_TGRA_1    0xfffe4388
-#else
-#define MTU2_TGRA_1    0xfffe438a
-#endif
-
-#define STBCR3         0xfffe0408
-
-#define MTU2_TSTR_CST1 (1 << 1)        /* Counter Start 1 */
-
-#define MTU2_TSR_TGFA  (1 << 0)        /* GRA compare match */
-
-#define MTU2_TIER_TGIEA        (1 << 0)        /* GRA compare match  interrupt enable */
-
-#define MTU2_TCR_INIT  0x22
-
-#define MTU2_TCR_CALIB  0x00
-
-static unsigned long mtu2_timer_get_offset(void)
-{
-       int count;
-       static int count_p = 0x7fff;    /* for the first call after boot */
-       static unsigned long jiffies_p = 0;
-
-       /*
-        * cache volatile jiffies temporarily; we have IRQs turned off.
-        */
-       unsigned long jiffies_t;
-
-       /* timer count may underflow right here */
-       count = ctrl_inw(MTU2_TCNT_1);  /* read the latched count */
-
-       jiffies_t = jiffies;
-
-       /*
-        * avoiding timer inconsistencies (they are rare, but they happen)...
-        * there is one kind of problem that must be avoided here:
-        *  1. the timer counter underflows
-        */
-
-       if (jiffies_t == jiffies_p) {
-               if (count > count_p) {
-                       if (ctrl_inb(MTU2_TSR_1) & MTU2_TSR_TGFA) {
-                               count -= LATCH;
-                       } else {
-                               printk("%s (): hardware timer problem?\n",
-                                      __func__);
-                       }
-               }
-       } else
-               jiffies_p = jiffies_t;
-
-       count_p = count;
-
-       count = ((LATCH-1) - count) * TICK_SIZE;
-       count = (count + LATCH/2) / LATCH;
-
-       return count;
-}
-
-static irqreturn_t mtu2_timer_interrupt(int irq, void *dev_id)
-{
-       unsigned long timer_status;
-
-       /* Clear TGFA bit */
-       timer_status = ctrl_inb(MTU2_TSR_1);
-       timer_status &= ~MTU2_TSR_TGFA;
-       ctrl_outb(timer_status, MTU2_TSR_1);
-
-       /* Do timer tick */
-       handle_timer_tick();
-
-       return IRQ_HANDLED;
-}
-
-static struct irqaction mtu2_irq = {
-       .name           = "timer",
-       .handler        = mtu2_timer_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-};
-
-static unsigned int divisors[] = { 1, 4, 16, 64, 1, 1, 256 };
-
-static void mtu2_clk_init(struct clk *clk)
-{
-       u8 idx = MTU2_TCR_INIT & 0x7;
-
-       clk->rate = clk->parent->rate / divisors[idx];
-       /* Start TCNT counting */
-       ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR);
-
-}
-
-static void mtu2_clk_recalc(struct clk *clk)
-{
-       u8 idx = ctrl_inb(MTU2_TCR_1) & 0x7;
-       clk->rate = clk->parent->rate / divisors[idx];
-}
-
-static struct clk_ops mtu2_clk_ops = {
-       .init           = mtu2_clk_init,
-       .recalc         = mtu2_clk_recalc,
-};
-
-static struct clk mtu2_clk1 = {
-       .name           = "mtu2_clk1",
-       .ops            = &mtu2_clk_ops,
-};
-
-static int mtu2_timer_start(void)
-{
-       ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR);
-       return 0;
-}
-
-static int mtu2_timer_stop(void)
-{
-       ctrl_outb(ctrl_inb(MTU2_TSTR) & ~MTU2_TSTR_CST1, MTU2_TSTR);
-       return 0;
-}
-
-static int mtu2_timer_init(void)
-{
-       unsigned long interval;
-
-       setup_irq(CONFIG_SH_TIMER_IRQ, &mtu2_irq);
-
-       mtu2_clk1.parent = clk_get(NULL, "module_clk");
-
-       ctrl_outb(ctrl_inb(STBCR3) & (~0x20), STBCR3);
-
-       /* Normal operation */
-       ctrl_outb(0, MTU2_TMDR_1);
-       ctrl_outb(MTU2_TCR_INIT, MTU2_TCR_1);
-       ctrl_outb(0x01, MTU2_TIOR_1);
-
-       /* Enable underflow interrupt */
-       ctrl_outb(ctrl_inb(MTU2_TIER_1) | MTU2_TIER_TGIEA, MTU2_TIER_1);
-
-       interval = CONFIG_SH_PCLK_FREQ / 16 / HZ;
-       printk(KERN_INFO "Interval = %ld\n", interval);
-
-       ctrl_outw(interval, MTU2_TGRA_1);
-       ctrl_outw(0, MTU2_TCNT_1);
-
-       clk_register(&mtu2_clk1);
-       clk_enable(&mtu2_clk1);
-
-       return 0;
-}
-
-struct sys_timer_ops mtu2_timer_ops = {
-       .init           = mtu2_timer_init,
-       .start          = mtu2_timer_start,
-       .stop           = mtu2_timer_stop,
-#ifndef CONFIG_GENERIC_TIME
-       .get_offset     = mtu2_timer_get_offset,
-#endif
-};
-
-struct sys_timer mtu2_timer = {
-       .name   = "mtu2",
-       .ops    = &mtu2_timer_ops,
-};
diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
deleted file mode 100644 (file)
index fe8d893..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * arch/sh/kernel/timers/timer-tmu.c - TMU Timer Support
- *
- *  Copyright (C) 2005 - 2007  Paul Mundt
- *
- * TMU handling code hacked out of arch/sh/kernel/time.c
- *
- *  Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
- *  Copyright (C) 2000  Philipp Rumpf <prumpf@tux.org>
- *  Copyright (C) 2002, 2003, 2004  Paul Mundt
- *  Copyright (C) 2002  M. R. Brown  <mrbrown@linux-sh.org>
- *
- * 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.
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/seqlock.h>
-#include <linux/clockchips.h>
-#include <asm/timer.h>
-#include <asm/rtc.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/clock.h>
-
-#define TMU_TOCR_INIT  0x00
-#define TMU_TCR_INIT   0x0020
-
-#define TMU0           (0)
-#define TMU1           (1)
-
-static inline void _tmu_start(int tmu_num)
-{
-       ctrl_outb(ctrl_inb(TMU_012_TSTR) | (0x1<<tmu_num), TMU_012_TSTR);
-}
-
-static inline void _tmu_set_irq(int tmu_num, int enabled)
-{
-       register unsigned long tmu_tcr = TMU0_TCR + (0xc*tmu_num);
-       ctrl_outw( (enabled ? ctrl_inw(tmu_tcr) | (1<<5) : ctrl_inw(tmu_tcr) & ~(1<<5)), tmu_tcr);
-}
-
-static inline void _tmu_stop(int tmu_num)
-{
-       ctrl_outb(ctrl_inb(TMU_012_TSTR) & ~(0x1<<tmu_num), TMU_012_TSTR);
-}
-
-static inline void _tmu_clear_status(int tmu_num)
-{
-       register unsigned long tmu_tcr = TMU0_TCR + (0xc*tmu_num);
-       /* Clear UNF bit */
-       ctrl_outw(ctrl_inw(tmu_tcr) & ~0x100, tmu_tcr);
-}
-
-static inline unsigned long _tmu_read(int tmu_num)
-{
-        return ctrl_inl(TMU0_TCNT+0xC*tmu_num);
-}
-
-static int tmu_timer_start(void)
-{
-       _tmu_start(TMU0);
-       _tmu_start(TMU1);
-       _tmu_set_irq(TMU0,1);
-       return 0;
-}
-
-static int tmu_timer_stop(void)
-{
-       _tmu_stop(TMU0);
-       _tmu_stop(TMU1);
-       _tmu_clear_status(TMU0);
-       return 0;
-}
-
-/*
- * also when the module_clk is scaled the TMU1
- * will show the same frequency
- */
-static int tmus_are_scaled;
-
-static cycle_t tmu_timer_read(struct clocksource *cs)
-{
-       return ((cycle_t)(~_tmu_read(TMU1)))<<tmus_are_scaled;
-}
-
-
-static unsigned long tmu_latest_interval[3];
-static void tmu_timer_set_interval(int tmu_num, unsigned long interval, unsigned int reload)
-{
-       unsigned long tmu_tcnt = TMU0_TCNT + tmu_num*0xC;
-       unsigned long tmu_tcor = TMU0_TCOR + tmu_num*0xC;
-
-       _tmu_stop(tmu_num);
-
-       ctrl_outl(interval, tmu_tcnt);
-       tmu_latest_interval[tmu_num] = interval;
-
-       /*
-        * TCNT reloads from TCOR on underflow, clear it if we don't
-        * intend to auto-reload
-        */
-       ctrl_outl( reload ? interval : 0 , tmu_tcor);
-
-       _tmu_start(tmu_num);
-}
-
-static int tmu_set_next_event(unsigned long cycles,
-                             struct clock_event_device *evt)
-{
-       tmu_timer_set_interval(TMU0,cycles, evt->mode == CLOCK_EVT_MODE_PERIODIC);
-       _tmu_set_irq(TMU0,1);
-       return 0;
-}
-
-static void tmu_set_mode(enum clock_event_mode mode,
-                        struct clock_event_device *evt)
-{
-       switch (mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
-               ctrl_outl(tmu_latest_interval[TMU0], TMU0_TCOR);
-               break;
-       case CLOCK_EVT_MODE_ONESHOT:
-               ctrl_outl(0, TMU0_TCOR);
-               break;
-       case CLOCK_EVT_MODE_UNUSED:
-       case CLOCK_EVT_MODE_SHUTDOWN:
-       case CLOCK_EVT_MODE_RESUME:
-               break;
-       }
-}
-
-static struct clock_event_device tmu0_clockevent = {
-       .name           = "tmu0",
-       .shift          = 32,
-       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-       .set_mode       = tmu_set_mode,
-       .set_next_event = tmu_set_next_event,
-};
-
-static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
-{
-       struct clock_event_device *evt = &tmu0_clockevent;
-       _tmu_clear_status(TMU0);
-       _tmu_set_irq(TMU0,tmu0_clockevent.mode != CLOCK_EVT_MODE_ONESHOT);
-
-       switch (tmu0_clockevent.mode) {
-       case CLOCK_EVT_MODE_ONESHOT:
-       case CLOCK_EVT_MODE_PERIODIC:
-               evt->event_handler(evt);
-               break;
-       default:
-               break;
-       }
-
-       return IRQ_HANDLED;
-}
-
-static struct irqaction tmu0_irq = {
-       .name           = "periodic/oneshot timer",
-       .handler        = tmu_timer_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-};
-
-static void __init tmu_clk_init(struct clk *clk)
-{
-       u8 divisor  = TMU_TCR_INIT & 0x7;
-       int tmu_num = clk->name[3]-'0';
-       ctrl_outw(TMU_TCR_INIT, TMU0_TCR+(tmu_num*0xC));
-       clk->rate = clk_get_rate(clk->parent) / (4 << (divisor << 1));
-}
-
-static void tmu_clk_recalc(struct clk *clk)
-{
-       int tmu_num = clk->name[3]-'0';
-       unsigned long prev_rate = clk_get_rate(clk);
-       unsigned long flags;
-       u8 divisor = ctrl_inw(TMU0_TCR+tmu_num*0xC) & 0x7;
-       clk->rate  = clk_get_rate(clk->parent) / (4 << (divisor << 1));
-
-       if(prev_rate==clk_get_rate(clk))
-               return;
-
-       if(tmu_num)
-               return; /* No more work on TMU1 */
-
-       local_irq_save(flags);
-       tmus_are_scaled = (prev_rate > clk->rate);
-
-       _tmu_stop(TMU0);
-
-       tmu0_clockevent.mult = div_sc(clk->rate, NSEC_PER_SEC,
-                               tmu0_clockevent.shift);
-       tmu0_clockevent.max_delta_ns =
-                       clockevent_delta2ns(-1, &tmu0_clockevent);
-       tmu0_clockevent.min_delta_ns =
-                       clockevent_delta2ns(1, &tmu0_clockevent);
-
-       if (tmus_are_scaled)
-               tmu_latest_interval[TMU0] >>= 1;
-       else
-               tmu_latest_interval[TMU0] <<= 1;
-
-       tmu_timer_set_interval(TMU0,
-               tmu_latest_interval[TMU0],
-               tmu0_clockevent.mode == CLOCK_EVT_MODE_PERIODIC);
-
-       _tmu_start(TMU0);
-
-       local_irq_restore(flags);
-}
-
-static struct clk_ops tmu_clk_ops = {
-       .init           = tmu_clk_init,
-       .recalc         = tmu_clk_recalc,
-};
-
-static struct clk tmu0_clk = {
-       .name           = "tmu0_clk",
-       .ops            = &tmu_clk_ops,
-};
-
-static struct clk tmu1_clk = {
-       .name           = "tmu1_clk",
-       .ops            = &tmu_clk_ops,
-};
-
-static int tmu_timer_init(void)
-{
-       unsigned long interval;
-       unsigned long frequency;
-
-       setup_irq(CONFIG_SH_TIMER_IRQ, &tmu0_irq);
-
-       tmu0_clk.parent = clk_get(NULL, "module_clk");
-       tmu1_clk.parent = clk_get(NULL, "module_clk");
-
-       tmu_timer_stop();
-
-#if !defined(CONFIG_CPU_SUBTYPE_SH7720) && \
-    !defined(CONFIG_CPU_SUBTYPE_SH7721) && \
-    !defined(CONFIG_CPU_SUBTYPE_SH7760) && \
-    !defined(CONFIG_CPU_SUBTYPE_SH7785) && \
-    !defined(CONFIG_CPU_SUBTYPE_SH7786) && \
-    !defined(CONFIG_CPU_SUBTYPE_SHX3)
-       ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
-#endif
-
-       clk_register(&tmu0_clk);
-       clk_register(&tmu1_clk);
-       clk_enable(&tmu0_clk);
-       clk_enable(&tmu1_clk);
-
-       frequency = clk_get_rate(&tmu0_clk);
-       interval = (frequency + HZ / 2) / HZ;
-
-       tmu_timer_set_interval(TMU0,interval, 1);
-       tmu_timer_set_interval(TMU1,~0,1);
-
-       _tmu_start(TMU1);
-
-       clocksource_sh.rating = 200;
-       clocksource_sh.mask = CLOCKSOURCE_MASK(32);
-       clocksource_sh.read = tmu_timer_read;
-       clocksource_sh.shift = 10;
-       clocksource_sh.mult = clocksource_hz2mult(clk_get_rate(&tmu1_clk),
-                                                 clocksource_sh.shift);
-       clocksource_sh.flags = CLOCK_SOURCE_IS_CONTINUOUS;
-       clocksource_register(&clocksource_sh);
-
-       tmu0_clockevent.mult = div_sc(frequency, NSEC_PER_SEC,
-                                     tmu0_clockevent.shift);
-       tmu0_clockevent.max_delta_ns =
-                       clockevent_delta2ns(-1, &tmu0_clockevent);
-       tmu0_clockevent.min_delta_ns =
-                       clockevent_delta2ns(1, &tmu0_clockevent);
-
-       tmu0_clockevent.cpumask = cpumask_of(0);
-       tmu0_clockevent.rating = 100;
-
-       clockevents_register_device(&tmu0_clockevent);
-
-       return 0;
-}
-
-static struct sys_timer_ops tmu_timer_ops = {
-       .init           = tmu_timer_init,
-       .start          = tmu_timer_start,
-       .stop           = tmu_timer_stop,
-};
-
-struct sys_timer tmu_timer = {
-       .name   = "tmu",
-       .ops    = &tmu_timer_ops,
-};
diff --git a/arch/sh/kernel/timers/timer.c b/arch/sh/kernel/timers/timer.c
deleted file mode 100644 (file)
index 4e7e747..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * arch/sh/kernel/timers/timer.c - Common timer code
- *
- *  Copyright (C) 2005  Paul Mundt
- *
- * 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.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <asm/timer.h>
-
-static struct sys_timer *sys_timers[] = {
-#ifdef CONFIG_SH_TMU
-       &tmu_timer,
-#endif
-#ifdef CONFIG_SH_MTU2
-       &mtu2_timer,
-#endif
-#ifdef CONFIG_SH_CMT
-       &cmt_timer,
-#endif
-       NULL,
-};
-
-static char timer_override[10];
-static int __init timer_setup(char *str)
-{
-       if (str)
-               strlcpy(timer_override, str, sizeof(timer_override));
-       return 1;
-}
-__setup("timer=", timer_setup);
-
-struct sys_timer *get_sys_timer(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(sys_timers); i++) {
-               struct sys_timer *t = sys_timers[i];
-
-               if (unlikely(!t))
-                       break;
-               if (unlikely(timer_override[0]))
-                       if ((strcmp(timer_override, t->name) != 0))
-                               continue;
-               if (likely(t->ops->init() == 0))
-                       return t;
-       }
-
-       return NULL;
-}
index 438f1ebcc45330cc0a5d320fee82a4b6840bcf1d..46348ed07cc35cde3b5120099bfd842d1ac0b7cd 100644 (file)
@@ -22,11 +22,11 @@ static void handle_BUG(struct pt_regs *regs)
 
 int is_valid_bugaddr(unsigned long addr)
 {
-       unsigned short opcode;
+       insn_size_t opcode;
 
        if (addr < PAGE_OFFSET)
                return 0;
-       if (probe_kernel_address((u16 *)addr, opcode))
+       if (probe_kernel_address((insn_size_t *)addr, opcode))
                return 0;
 
        return opcode == TRAPA_BUG_OPCODE;
@@ -66,7 +66,7 @@ BUILD_TRAP_HANDLER(bug)
 
 #ifdef CONFIG_BUG
        if (__kernel_text_address(instruction_pointer(regs))) {
-               opcode_t insn = *(opcode_t *)instruction_pointer(regs);
+               insn_size_t insn = *(insn_size_t *)instruction_pointer(regs);
                if (insn == TRAPA_BUG_OPCODE)
                        handle_BUG(regs);
        }
index 30ca9c51e52db677ac1f2d0cf0b5da287a78c466..2b772776fcda9e50cf6d7dfe0373668ad52307bb 100644 (file)
@@ -34,6 +34,7 @@
 # define TRAP_ILLEGAL_SLOT_INST        6
 # define TRAP_ADDRESS_ERROR    9
 # ifdef CONFIG_CPU_SH2A
+#  define TRAP_UBC             12
 #  define TRAP_FPU_ERROR       13
 #  define TRAP_DIVZERO_ERROR   17
 #  define TRAP_DIVOVF_ERROR    18
@@ -176,7 +177,7 @@ static struct mem_access user_mem_access = {
  *   (if that instruction is in a branch delay slot)
  * - return 0 if emulation okay, -EFAULT on existential error
  */
-static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs,
+static int handle_unaligned_ins(insn_size_t instruction, struct pt_regs *regs,
                                struct mem_access *ma)
 {
        int ret, index, count;
@@ -321,10 +322,10 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs,
  * - fetches the instruction from PC+2
  */
 static inline int handle_delayslot(struct pt_regs *regs,
-                                  opcode_t old_instruction,
+                                  insn_size_t old_instruction,
                                   struct mem_access *ma)
 {
-       opcode_t instruction;
+       insn_size_t instruction;
        void __user *addr = (void __user *)(regs->pc +
                instruction_size(old_instruction));
 
@@ -364,7 +365,7 @@ static inline int handle_delayslot(struct pt_regs *regs,
 
 static int handle_unaligned_notify_count = 10;
 
-int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs,
+int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
                            struct mem_access *ma)
 {
        u_int rm;
@@ -522,7 +523,7 @@ asmlinkage void do_address_error(struct pt_regs *regs,
        unsigned long error_code = 0;
        mm_segment_t oldfs;
        siginfo_t info;
-       opcode_t instruction;
+       insn_size_t instruction;
        int tmp;
 
        /* Intentional ifdef */
@@ -849,6 +850,10 @@ void __init trap_init(void)
 #endif
 #endif
 
+#ifdef TRAP_UBC
+       set_exception_table_vec(TRAP_UBC, break_point_trap);
+#endif
+
        /* Setup VBR for boot cpu */
        per_cpu_trap_init();
 }
index a85831cbf18ba6524968f8c3e7dfa6a1bc6025d9..267e5ebbb4753c921a1df63ff1cb43f649228b3f 100644 (file)
@@ -370,7 +370,6 @@ static int generate_and_check_address(struct pt_regs *regs,
                return -1;
        }
 
-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
        /* Check accessible.  For misaligned access in the kernel, assume the
           address is always accessible (and if not, just fault when the
           load/store gets done.) */
@@ -380,18 +379,13 @@ static int generate_and_check_address(struct pt_regs *regs,
                }
                /* Do access_ok check later - it depends on whether it's a load or a store. */
        }
-#endif
 
        *address = addr;
        return 0;
 }
 
-/* Default value as for sh */
-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
 static int user_mode_unaligned_fixup_count = 10;
 static int user_mode_unaligned_fixup_enable = 1;
-#endif
-
 static int kernel_mode_unaligned_fixup_count = 32;
 
 static void misaligned_kernel_word_load(__u64 address, int do_sign_extend, __u64 *result)
@@ -440,7 +434,6 @@ static int misaligned_load(struct pt_regs *regs,
        }
 
        destreg = (opcode >> 4) & 0x3f;
-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
        if (user_mode(regs)) {
                __u64 buffer;
 
@@ -470,9 +463,7 @@ static int misaligned_load(struct pt_regs *regs,
                                width_shift, (unsigned long) regs->pc);
                        break;
                }
-       } else
-#endif
-       {
+       } else {
                /* kernel mode - we can take short cuts since if we fault, it's a genuine bug */
                __u64 lo, hi;
 
@@ -519,7 +510,6 @@ static int misaligned_store(struct pt_regs *regs,
        }
 
        srcreg = (opcode >> 4) & 0x3f;
-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
        if (user_mode(regs)) {
                __u64 buffer;
 
@@ -546,9 +536,7 @@ static int misaligned_store(struct pt_regs *regs,
                if (__copy_user((void *)(int)address, &buffer, (1 << width_shift)) > 0) {
                        return -1; /* fault */
                }
-       } else
-#endif
-       {
+       } else {
                /* kernel mode - we can take short cuts since if we fault, it's a genuine bug */
                __u64 val = regs->regs[srcreg];
 
@@ -576,7 +564,6 @@ static int misaligned_store(struct pt_regs *regs,
 
 }
 
-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
 /* Never need to fix up misaligned FPU accesses within the kernel since that's a real
    error. */
 static int misaligned_fpu_load(struct pt_regs *regs,
@@ -727,7 +714,6 @@ static int misaligned_fpu_store(struct pt_regs *regs,
                return -1;
        }
 }
-#endif
 
 static int misaligned_fixup(struct pt_regs *regs)
 {
@@ -735,12 +721,8 @@ static int misaligned_fixup(struct pt_regs *regs)
        int error;
        int major, minor;
 
-#if !defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
-       /* Never fixup user mode misaligned accesses without this option enabled. */
-       return -1;
-#else
-       if (!user_mode_unaligned_fixup_enable) return -1;
-#endif
+       if (!user_mode_unaligned_fixup_enable)
+               return -1;
 
        error = read_opcode(regs->pc, &opcode, user_mode(regs));
        if (error < 0) {
@@ -749,15 +731,12 @@ static int misaligned_fixup(struct pt_regs *regs)
        major = (opcode >> 26) & 0x3f;
        minor = (opcode >> 16) & 0xf;
 
-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
        if (user_mode(regs) && (user_mode_unaligned_fixup_count > 0)) {
                --user_mode_unaligned_fixup_count;
                /* Only do 'count' worth of these reports, to remove a potential DoS against syslog */
                printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%08x ins=0x%08lx\n",
                       current->comm, task_pid_nr(current), (__u32)regs->pc, opcode);
-       } else
-#endif
-       if (!user_mode(regs) && (kernel_mode_unaligned_fixup_count > 0)) {
+       } else if (!user_mode(regs) && (kernel_mode_unaligned_fixup_count > 0)) {
                --kernel_mode_unaligned_fixup_count;
                if (in_interrupt()) {
                        printk("Fixing up unaligned kernelspace access in interrupt pc=0x%08x ins=0x%08lx\n",
@@ -830,7 +809,6 @@ static int misaligned_fixup(struct pt_regs *regs)
                        }
                        break;
 
-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
                case (0x94>>2): /* FLD.S */
                        error = misaligned_fpu_load(regs, opcode, 1, 2, 0);
                        break;
@@ -881,7 +859,6 @@ static int misaligned_fixup(struct pt_regs *regs)
                                break;
                        }
                        break;
-#endif
 
                default:
                        /* Fault */
@@ -907,7 +884,6 @@ static ctl_table unaligned_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec
        },
-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
        {
                .ctl_name       = CTL_UNNUMBERED,
                .procname       = "user_reports",
@@ -923,7 +899,6 @@ static ctl_table unaligned_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = &proc_dointvec},
-#endif
        {}
 };
 
index d7d4991f32af2dd3c01fed156a9061d2079ad7a9..f53c76acaede2f1af80aaec431e53308c4681bee 100644 (file)
@@ -1,5 +1,178 @@
-#ifdef CONFIG_SUPERH32
-# include "vmlinux_32.lds.S"
+/*
+ * ld script to make SuperH Linux kernel
+ * Written by Niibe Yutaka and Paul Mundt
+ */
+#ifdef CONFIG_SUPERH64
+#define LOAD_OFFSET    CONFIG_PAGE_OFFSET
+OUTPUT_ARCH(sh:sh5)
 #else
-# include "vmlinux_64.lds.S"
+#define LOAD_OFFSET    0
+OUTPUT_ARCH(sh)
 #endif
+
+#include <asm/thread_info.h>
+#include <asm/cache.h>
+#include <asm-generic/vmlinux.lds.h>
+
+ENTRY(_start)
+SECTIONS
+{
+#ifdef CONFIG_PMB_FIXED
+       . = CONFIG_PAGE_OFFSET + (CONFIG_MEMORY_START & 0x1fffffff) +
+           CONFIG_ZERO_PAGE_OFFSET;
+#elif defined(CONFIG_32BIT)
+       . = CONFIG_PAGE_OFFSET + CONFIG_ZERO_PAGE_OFFSET;
+#else
+       . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET;
+#endif
+
+       _text = .;              /* Text and read-only data */
+
+       .empty_zero_page : AT(ADDR(.empty_zero_page) - LOAD_OFFSET) {
+               *(.empty_zero_page)
+       } = 0
+
+       .text : AT(ADDR(.text) - LOAD_OFFSET) {
+               HEAD_TEXT
+               TEXT_TEXT
+
+#ifdef CONFIG_SUPERH64
+               *(.text64)
+               *(.text..SHmedia32)
+#endif
+
+               SCHED_TEXT
+               LOCK_TEXT
+               KPROBES_TEXT
+               IRQENTRY_TEXT
+               *(.fixup)
+               *(.gnu.warning)
+               _etext = .;             /* End of text section */
+       } = 0x0009
+
+       . = ALIGN(16);          /* Exception table */
+       __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
+               __start___ex_table = .;
+               *(__ex_table)
+               __stop___ex_table = .;
+       }
+
+       NOTES
+       RO_DATA(PAGE_SIZE)
+
+       /*
+        * Code which must be executed uncached and the associated data
+        */
+       . = ALIGN(PAGE_SIZE);
+       .uncached : AT(ADDR(.uncached) - LOAD_OFFSET) {
+               __uncached_start = .;
+               *(.uncached.text)
+               *(.uncached.data)
+               __uncached_end = .;
+       }
+
+       . = ALIGN(THREAD_SIZE);
+       .data : AT(ADDR(.data) - LOAD_OFFSET) {         /* Data */
+               *(.data.init_task)
+
+               . = ALIGN(L1_CACHE_BYTES);
+               *(.data.cacheline_aligned)
+
+               . = ALIGN(L1_CACHE_BYTES);
+               *(.data.read_mostly)
+
+               . = ALIGN(PAGE_SIZE);
+               *(.data.page_aligned)
+
+               __nosave_begin = .;
+               *(.data.nosave)
+               . = ALIGN(PAGE_SIZE);
+               __nosave_end = .;
+
+               DATA_DATA
+               CONSTRUCTORS
+       }
+
+       _edata = .;                     /* End of data section */
+
+       . = ALIGN(PAGE_SIZE);           /* Init code and data */
+       .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
+               __init_begin = .;
+               _sinittext = .;
+               INIT_TEXT
+               _einittext = .;
+       }
+
+       .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { INIT_DATA }
+
+       . = ALIGN(16);
+       .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
+               __setup_start = .;
+               *(.init.setup)
+               __setup_end = .;
+       }
+
+       .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
+               __initcall_start = .;
+               INITCALLS
+               __initcall_end = .;
+       }
+
+       .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
+               __con_initcall_start = .;
+               *(.con_initcall.init)
+               __con_initcall_end = .;
+       }
+
+       SECURITY_INIT
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       . = ALIGN(PAGE_SIZE);
+       .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
+               __initramfs_start = .;
+               *(.init.ramfs)
+               __initramfs_end = .;
+       }
+#endif
+
+       . = ALIGN(4);
+       .machvec.init : AT(ADDR(.machvec.init) - LOAD_OFFSET) {
+               __machvec_start = .;
+               *(.machvec.init)
+               __machvec_end = .;
+       }
+
+       PERCPU(PAGE_SIZE)
+
+       /*
+        * .exit.text is discarded at runtime, not link time, to deal with
+        * references from __bug_table
+        */
+       .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { EXIT_TEXT }
+       .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { EXIT_DATA }
+
+       . = ALIGN(PAGE_SIZE);
+       .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
+               __init_end = .;
+               __bss_start = .;                /* BSS */
+               *(.bss.page_aligned)
+               *(.bss)
+               *(COMMON)
+               . = ALIGN(4);
+               _ebss = .;                      /* uClinux MTD sucks */
+               _end = . ;
+       }
+
+       /*
+        * When something in the kernel is NOT compiled as a module, the
+        * module cleanup code and data are put into these segments. Both
+        * can then be thrown away, as cleanup code is never called unless
+        * it's a module.
+        */
+       /DISCARD/ : {
+               *(.exitcall.exit)
+       }
+
+       STABS_DEBUG
+       DWARF_DEBUG
+}
diff --git a/arch/sh/kernel/vmlinux_32.lds.S b/arch/sh/kernel/vmlinux_32.lds.S
deleted file mode 100644 (file)
index dd9b2ee..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * ld script to make SuperH Linux kernel
- * Written by Niibe Yutaka
- */
-#include <asm/thread_info.h>
-#include <asm/cache.h>
-#include <asm-generic/vmlinux.lds.h>
-
-#ifdef CONFIG_CPU_LITTLE_ENDIAN
-OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux")
-#else
-OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux")
-#endif
-OUTPUT_ARCH(sh)
-ENTRY(_start)
-SECTIONS
-{
-#ifdef CONFIG_PMB_FIXED
-       . = CONFIG_PAGE_OFFSET + (CONFIG_MEMORY_START & 0x1fffffff) +
-           CONFIG_ZERO_PAGE_OFFSET;
-#elif defined(CONFIG_32BIT)
-       . = CONFIG_PAGE_OFFSET + CONFIG_ZERO_PAGE_OFFSET;
-#else
-       . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET;
-#endif
-
-       _text = .;                      /* Text and read-only data */
-
-       .empty_zero_page : {
-               *(.empty_zero_page)
-       } = 0
-
-       .text : {
-               HEAD_TEXT
-               TEXT_TEXT
-               SCHED_TEXT
-               LOCK_TEXT
-               KPROBES_TEXT
-               *(.fixup)
-               *(.gnu.warning)
-       } = 0x0009
-
-       . = ALIGN(16);          /* Exception table */
-       __start___ex_table = .;
-       __ex_table : { *(__ex_table) }
-       __stop___ex_table = .;
-
-       _etext = .;                     /* End of text section */
-
-       NOTES
-       RO_DATA(PAGE_SIZE)
-
-       /*
-        * Code which must be executed uncached and the associated data
-        */
-       . = ALIGN(PAGE_SIZE);
-       __uncached_start = .;
-       .uncached.text : { *(.uncached.text) }
-       .uncached.data : { *(.uncached.data) }
-       __uncached_end = .;
-
-       . = ALIGN(THREAD_SIZE);
-       .data : {                       /* Data */
-               *(.data.init_task)
-
-               . = ALIGN(L1_CACHE_BYTES);
-               *(.data.cacheline_aligned)
-
-               . = ALIGN(L1_CACHE_BYTES);
-               *(.data.read_mostly)
-
-               . = ALIGN(PAGE_SIZE);
-               *(.data.page_aligned)
-
-               __nosave_begin = .;
-               *(.data.nosave)
-               . = ALIGN(PAGE_SIZE);
-               __nosave_end = .;
-
-               DATA_DATA
-               CONSTRUCTORS
-       }
-
-       _edata = .;                     /* End of data section */
-
-       . = ALIGN(PAGE_SIZE);           /* Init code and data */
-       __init_begin = .;
-       _sinittext = .;
-       .init.text : { INIT_TEXT }
-       _einittext = .;
-       .init.data : { INIT_DATA }
-
-       . = ALIGN(16);
-       __setup_start = .;
-       .init.setup : { *(.init.setup) }
-       __setup_end = .;
-
-       __initcall_start = .;
-       .initcall.init : {
-               INITCALLS
-       }
-       __initcall_end = .;
-       __con_initcall_start = .;
-       .con_initcall.init : { *(.con_initcall.init) }
-       __con_initcall_end = .;
-
-       SECURITY_INIT
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       . = ALIGN(PAGE_SIZE);
-       __initramfs_start = .;
-       .init.ramfs : { *(.init.ramfs) }
-       __initramfs_end = .;
-#endif
-
-       . = ALIGN(4);
-       __machvec_start = .;
-       .machvec.init : { *(.machvec.init) }
-       __machvec_end = .;
-
-       PERCPU(PAGE_SIZE)
-
-       /*
-        * .exit.text is discarded at runtime, not link time, to deal with
-        * references from __bug_table
-        */
-       .exit.text : { EXIT_TEXT }
-       .exit.data : { EXIT_DATA }
-
-       . = ALIGN(PAGE_SIZE);
-       .bss : {
-               __init_end = .;
-               __bss_start = .;                /* BSS */
-               *(.bss.page_aligned)
-               *(.bss)
-               *(COMMON)
-               . = ALIGN(4);
-               _ebss = .;                      /* uClinux MTD sucks */
-               _end = . ;
-       }
-
-       /*
-        * When something in the kernel is NOT compiled as a module, the
-        * module cleanup code and data are put into these segments. Both
-        * can then be thrown away, as cleanup code is never called unless
-        * it's a module.
-        */
-       /DISCARD/ : {
-               *(.exitcall.exit)
-       }
-
-       STABS_DEBUG
-       DWARF_DEBUG
-}
diff --git a/arch/sh/kernel/vmlinux_64.lds.S b/arch/sh/kernel/vmlinux_64.lds.S
deleted file mode 100644 (file)
index 6966446..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * ld script to make SH64 Linux kernel
- *
- * Copyright (C) 2000, 2001  Paolo Alberelli
- *
- * benedict.gaster@superh.com:  2nd May 2002
- *    Add definition of empty_zero_page to be the first page of kernel image.
- *
- * benedict.gaster@superh.com:  3rd May 2002
- *    Added support for ramdisk, removing statically linked romfs at the
- *    same time.
- *
- * lethal@linux-sh.org:          9th May 2003
- *    Kill off GLOBAL_NAME() usage and other CDC-isms.
- *
- * lethal@linux-sh.org:         19th May 2003
- *    Remove support for ancient toolchains.
- *
- * 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.
- */
-#include <asm/page.h>
-#include <asm/cache.h>
-#include <asm/thread_info.h>
-
-#define LOAD_OFFSET    CONFIG_PAGE_OFFSET
-#include <asm-generic/vmlinux.lds.h>
-
-OUTPUT_ARCH(sh:sh5)
-
-#define C_PHYS(x) AT (ADDR(x) - LOAD_OFFSET)
-
-ENTRY(__start)
-SECTIONS
-{
-       . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + PAGE_SIZE;
-       _text = .;                      /* Text and read-only data */
-
-       .empty_zero_page : C_PHYS(.empty_zero_page) {
-               *(.empty_zero_page)
-       } = 0
-
-       .text : C_PHYS(.text) {
-               HEAD_TEXT
-               TEXT_TEXT
-               *(.text64)
-               *(.text..SHmedia32)
-               SCHED_TEXT
-               LOCK_TEXT
-               KPROBES_TEXT
-               *(.fixup)
-               *(.gnu.warning)
-#ifdef CONFIG_CPU_LITTLE_ENDIAN
-       } = 0x6ff0fff0
-#else
-       } = 0xf0fff06f
-#endif
-
-       /* We likely want __ex_table to be Cache Line aligned */
-       . = ALIGN(L1_CACHE_BYTES);              /* Exception table */
-       __start___ex_table = .;
-       __ex_table : C_PHYS(__ex_table) { *(__ex_table) }
-       __stop___ex_table = .;
-
-       _etext = .;                     /* End of text section */
-
-       NOTES 
-       RO_DATA(PAGE_SIZE)
-
-       . = ALIGN(THREAD_SIZE);
-       .data : C_PHYS(.data) {                 /* Data */
-               *(.data.init_task)
-
-               . = ALIGN(L1_CACHE_BYTES);
-               *(.data.cacheline_aligned)
-
-               . = ALIGN(L1_CACHE_BYTES);
-               *(.data.read_mostly)
-
-               . = ALIGN(PAGE_SIZE);
-               *(.data.page_aligned)
-
-               __nosave_begin = .;
-               *(.data.nosave)
-               . = ALIGN(PAGE_SIZE);
-               __nosave_end = .;
-
-               DATA_DATA
-               CONSTRUCTORS
-       }
-
-       _edata = .;                     /* End of data section */
-
-       . = ALIGN(PAGE_SIZE);           /* Init code and data */
-       __init_begin = .;
-       _sinittext = .;
-       .init.text : C_PHYS(.init.text) { INIT_TEXT }
-       _einittext = .;
-       .init.data : C_PHYS(.init.data) { INIT_DATA }
-       . = ALIGN(L1_CACHE_BYTES);      /* Better if Cache Line aligned */
-       __setup_start = .;
-       .init.setup : C_PHYS(.init.setup) { *(.init.setup) }
-       __setup_end = .;
-       __initcall_start = .;
-       .initcall.init : C_PHYS(.initcall.init) {
-               INITCALLS
-       }
-       __initcall_end = .;
-       __con_initcall_start = .;
-       .con_initcall.init : C_PHYS(.con_initcall.init) {
-               *(.con_initcall.init)
-       }
-       __con_initcall_end = .;
-
-       SECURITY_INIT
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       . = ALIGN(PAGE_SIZE);
-       __initramfs_start = .;
-       .init.ramfs : C_PHYS(.init.ramfs) { *(.init.ramfs) }
-       __initramfs_end = .;
-#endif
-
-       . = ALIGN(8);
-       __machvec_start = .;
-       .machvec.init : C_PHYS(.machvec.init) { *(.machvec.init) }
-       __machvec_end = .;
-
-       PERCPU(PAGE_SIZE)
-
-       /*
-        * .exit.text is discarded at runtime, not link time, to deal with
-        * references from __bug_table
-        */
-       .exit.text : C_PHYS(.exit.text) { EXIT_TEXT }
-       .exit.data : C_PHYS(.exit.data) { EXIT_DATA }
-
-       . = ALIGN(PAGE_SIZE);
-       .bss : C_PHYS(.bss) {
-               __init_end = .;
-               __bss_start = .;                /* BSS */
-               *(.bss.page_aligned)
-               *(.bss)
-               *(COMMON)
-               . = ALIGN(4);
-               _ebss = .;                      /* uClinux MTD sucks */
-               _end = . ;
-       }
-
-       /*
-        * When something in the kernel is NOT compiled as a module, the
-        * module cleanup code and data are put into these segments. Both
-        * can then be thrown away, as cleanup code is never called unless
-        * it's a module.
-        */
-       /DISCARD/ : {
-               *(.exitcall.exit)
-       }
-
-       STABS_DEBUG
-       DWARF_DEBUG
-}
diff --git a/arch/sh/lib64/.gitignore b/arch/sh/lib64/.gitignore
deleted file mode 100644 (file)
index 3508c2c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-syscalltab.h
index 2fb8eaf6de60a01c6bbaae80d7839b0a2d1778bc..6152a6a6d9c6e17309ece74b15dc807c8cd78205 100644 (file)
@@ -135,140 +135,6 @@ void print_itlb(void)
            (" =============================================================\n");
 }
 
-/* ======================================================================= */
-
-#ifdef CONFIG_POOR_MANS_STRACE
-
-#include "syscalltab.h"
-
-struct ring_node {
-       int evt;
-       int ret_addr;
-       int event;
-       int tra;
-       int pid;
-       unsigned long sp;
-       unsigned long pc;
-};
-
-static struct ring_node event_ring[16];
-static int event_ptr = 0;
-
-struct stored_syscall_data {
-       int pid;
-       int syscall_number;
-};
-
-#define N_STORED_SYSCALLS 16
-
-static struct stored_syscall_data stored_syscalls[N_STORED_SYSCALLS];
-static int syscall_next=0;
-static int syscall_next_print=0;
-
-void evt_debug(int evt, int ret_addr, int event, int tra, struct pt_regs *regs)
-{
-       int syscallno = tra & 0xff;
-       unsigned long sp;
-       unsigned long stack_bottom;
-       int pid;
-       struct ring_node *rr;
-
-       pid = current->pid;
-       stack_bottom = (unsigned long) task_stack_page(current);
-       asm volatile("ori r15, 0, %0" : "=r" (sp));
-       rr = event_ring + event_ptr;
-       rr->evt = evt;
-       rr->ret_addr = ret_addr;
-       rr->event = event;
-       rr->tra = tra;
-       rr->pid = pid;
-       rr->sp = sp;
-       rr->pc = regs->pc;
-
-       if (sp < stack_bottom + 3092) {
-               int i, j;
-               printk("evt_debug : stack underflow report\n");
-               for (j=0, i = event_ptr; j<16; j++) {
-                       rr = event_ring + i;
-                       printk("evt=%08x event=%08x tra=%08x pid=%5d sp=%08lx pc=%08lx\n",
-                               rr->evt, rr->event, rr->tra, rr->pid, rr->sp, rr->pc);
-                       i--;
-                       i &= 15;
-               }
-               panic("STACK UNDERFLOW\n");
-       }
-
-       event_ptr = (event_ptr + 1) & 15;
-
-       if ((event == 2) && (evt == 0x160)) {
-               if (syscallno < NUM_SYSCALL_INFO_ENTRIES) {
-                       /* Store the syscall information to print later.  We
-                        * can't print this now - currently we're running with
-                        * SR.BL=1, so we can't take a tlbmiss (which could occur
-                        * in the console drivers under printk).
-                        *
-                        * Just overwrite old entries on ring overflow - this
-                        * is only for last-hope debugging. */
-                       stored_syscalls[syscall_next].pid = current->pid;
-                       stored_syscalls[syscall_next].syscall_number = syscallno;
-                       syscall_next++;
-                       syscall_next &= (N_STORED_SYSCALLS - 1);
-               }
-       }
-}
-
-static void drain_syscalls(void) {
-       while (syscall_next_print != syscall_next) {
-               printk("Task %d: %s()\n",
-                       stored_syscalls[syscall_next_print].pid,
-                       syscall_info_table[stored_syscalls[syscall_next_print].syscall_number].name);
-                       syscall_next_print++;
-                       syscall_next_print &= (N_STORED_SYSCALLS - 1);
-       }
-}
-
-void evt_debug2(unsigned int ret)
-{
-       drain_syscalls();
-       printk("Task %d: syscall returns %08x\n", current->pid, ret);
-}
-
-void evt_debug_ret_from_irq(struct pt_regs *regs)
-{
-       int pid;
-       struct ring_node *rr;
-
-       pid = current->pid;
-       rr = event_ring + event_ptr;
-       rr->evt = 0xffff;
-       rr->ret_addr = 0;
-       rr->event = 0;
-       rr->tra = 0;
-       rr->pid = pid;
-       rr->pc = regs->pc;
-       event_ptr = (event_ptr + 1) & 15;
-}
-
-void evt_debug_ret_from_exc(struct pt_regs *regs)
-{
-       int pid;
-       struct ring_node *rr;
-
-       pid = current->pid;
-       rr = event_ring + event_ptr;
-       rr->evt = 0xfffe;
-       rr->ret_addr = 0;
-       rr->event = 0;
-       rr->tra = 0;
-       rr->pid = pid;
-       rr->pc = regs->pc;
-       event_ptr = (event_ptr + 1) & 15;
-}
-
-#endif /* CONFIG_POOR_MANS_STRACE */
-
-/* ======================================================================= */
-
 void show_excp_regs(char *from, int trapnr, int signr, struct pt_regs *regs)
 {
 
@@ -380,51 +246,3 @@ void show_excp_regs(char *from, int trapnr, int signr, struct pt_regs *regs)
        print_dtlb();
        print_itlb();
 }
-
-/* ======================================================================= */
-
-/*
-** Depending on <base> scan the MMU, Data or Instruction side
-** looking for a valid mapping matching Eaddr & asid.
-** Return -1 if not found or the TLB id entry otherwise.
-** Note: it works only for 4k pages!
-*/
-static unsigned long
-lookup_mmu_side(unsigned long base, unsigned long Eaddr, unsigned long asid)
-{
-       regType_t pteH;
-       unsigned long epn;
-       int count;
-
-       epn = Eaddr & 0xfffff000;
-
-       for (count = 0; count < MAX_TLBs; count++, base += TLB_STEP) {
-               pteH = getConfigReg(base);
-               if (GET_VALID(pteH))
-                       if ((unsigned long) GET_EPN(pteH) == epn)
-                               if ((unsigned long) GET_ASID(pteH) == asid)
-                                       break;
-       }
-       return ((unsigned long) ((count < MAX_TLBs) ? base : -1));
-}
-
-unsigned long lookup_dtlb(unsigned long Eaddr)
-{
-       unsigned long asid = get_asid();
-       return (lookup_mmu_side((u64) DTLB_BASE, Eaddr, asid));
-}
-
-unsigned long lookup_itlb(unsigned long Eaddr)
-{
-       unsigned long asid = get_asid();
-       return (lookup_mmu_side((u64) ITLB_BASE, Eaddr, asid));
-}
-
-void print_page(struct page *page)
-{
-       printk("  page[%p] -> index 0x%lx,  count 0x%x,  flags 0x%lx\n",
-              page, page->index, page_count(page), page->flags);
-       printk("       address_space = %p, pages =%ld\n", page->mapping,
-              page->mapping->nrpages);
-
-}
index da32ba7b5fcc0b6e12c91cd270d0d7fb33a8b477..38c954e04f6a5225b6562ec08983571c8a587961 100644 (file)
@@ -6,53 +6,10 @@
  * for more details.
  */
 
-#include <linux/kernel.h>
-#include <asm/io.h>
-#include <cpu/registers.h>
-
-/* THIS IS A PHYSICAL ADDRESS */
-#define HDSP2534_ADDR (0x04002100)
-
-#ifdef CONFIG_SH_CAYMAN
-
-static void poor_mans_delay(void)
-{
-       int i;
-       for (i = 0; i < 2500000; i++) {
-       }               /* poor man's delay */
-}
-
-static void show_value(unsigned long x)
-{
-       int i;
-       unsigned nibble;
-       for (i = 0; i < 8; i++) {
-               nibble = ((x >> (i * 4)) & 0xf);
-
-               ctrl_outb(nibble + ((nibble > 9) ? 55 : 48),
-                         HDSP2534_ADDR + 0xe0 + ((7 - i) << 2));
-       }
-}
-
-#endif
-
 void
 panic_handler(unsigned long panicPC, unsigned long panicSSR,
              unsigned long panicEXPEVT)
 {
-#ifdef CONFIG_SH_CAYMAN
-       while (1) {
-               /* This piece of code displays the PC on the LED display */
-               show_value(panicPC);
-               poor_mans_delay();
-               show_value(panicSSR);
-               poor_mans_delay();
-               show_value(panicEXPEVT);
-               poor_mans_delay();
-       }
-#endif
-
        /* Never return from the panic handler */
        for (;;) ;
-
 }
index 6a800c6a4904337a40e2bdff2618a402ae22261c..1963bbd42288d38d4f751f7a750cec1ee27f83bb 100644 (file)
@@ -1,4 +1,6 @@
        .global __sdivsi3
+       .global __sdivsi3_1
+       .global __sdivsi3_2
        .section        .text..SHmedia32,"ax"
        .align  2
 
@@ -6,13 +8,15 @@
        /* clobbered: r1,r18,r19,r20,r21,r25,tr0 */
        /* result in r0 */
 __sdivsi3:
+__sdivsi3_1:
        ptb __div_table,tr0
+       gettr tr0,r20
 
+__sdivsi3_2:
        nsb r5, r1
        shlld r5, r1, r25    /* normalize; [-2 ..1, 1..2) in s2.62 */
        shari r25, 58, r21   /* extract 5(6) bit index (s2.4 with hole -1..1) */
        /* bubble */
-       gettr tr0,r20
        ldx.ub r20, r21, r19 /* u0.8 */
        shari r25, 32, r25   /* normalize to s2.30 */
        shlli r21, 1, r21
index d76bd801194f538972219b3682e90ed77ffa3cb3..f215b063da704a305ad40717916d23a809de2a29 100644 (file)
@@ -33,7 +33,7 @@ void __delay(unsigned long loops)
                             :"0"(loops));
 }
 
-inline void __const_udelay(unsigned long xloops)
+void __const_udelay(unsigned long xloops)
 {
        __delay(xloops * (HZ * cpu_data[raw_smp_processor_id()].loops_per_jiffy));
 }
index d4079cab2d581c27621cfa645773d3bad2a7e3c7..2795618e4f072ba4d0c04c4841c0d90606fb4f94 100644 (file)
@@ -21,6 +21,29 @@ config PAGE_OFFSET
        default "0x20000000" if MMU && SUPERH64
        default "0x00000000"
 
+config FORCE_MAX_ZONEORDER
+       int "Maximum zone order"
+       range 9 64 if PAGE_SIZE_16KB
+       default "9" if PAGE_SIZE_16KB
+       range 7 64 if PAGE_SIZE_64KB
+       default "7" if PAGE_SIZE_64KB
+       range 11 64
+       default "14" if !MMU
+       default "11"
+       help
+         The kernel memory allocator divides physically contiguous memory
+         blocks into "zones", where each zone is a power of two number of
+         pages.  This option selects the largest power of two that the kernel
+         keeps in the memory allocator.  If you need to allocate very large
+         blocks of physically contiguous memory, then you may need to
+         increase this value.
+
+         This config option is actually maximum order plus one. For example,
+         a value of 11 means that the largest free memory block is 2^10 pages.
+
+         The page size is not necessarily 4KB. Keep this in mind when
+         choosing a value for this option.
+
 config MEMORY_START
        hex "Physical memory start address"
        default "0x08000000"
@@ -201,14 +224,6 @@ config PAGE_SIZE_64KB
 
 endchoice
 
-config ENTRY_OFFSET
-       hex
-       default "0x00001000" if PAGE_SIZE_4KB
-       default "0x00002000" if PAGE_SIZE_8KB
-       default "0x00004000" if PAGE_SIZE_16KB
-       default "0x00010000" if PAGE_SIZE_64KB
-       default "0x00000000"
-
 choice
        prompt "HugeTLB page size"
        depends on HUGETLB_PAGE && (CPU_SH4 || CPU_SH5) && MMU
index 9e277ec7d5360e1b46e0a7ee0b934e9e8a75c08c..86762092508c4d12535cae098a54c693c212baeb 100644 (file)
@@ -60,7 +60,7 @@ static inline void sh64_teardown_dtlb_cache_slot(void)
 static inline void sh64_icache_inv_all(void)
 {
        unsigned long long addr, flag, data;
-       unsigned int flags;
+       unsigned long flags;
 
        addr = ICCR0;
        flag = ICCR0_ICI;
@@ -172,7 +172,7 @@ static void sh64_icache_inv_user_page_range(struct mm_struct *mm,
                unsigned long eaddr;
                unsigned long after_last_page_start;
                unsigned long mm_asid, current_asid;
-               unsigned long long flags = 0ULL;
+               unsigned long flags = 0;
 
                mm_asid = cpu_asid(smp_processor_id(), mm);
                current_asid = get_asid();
@@ -236,7 +236,7 @@ static void sh64_icache_inv_user_small_range(struct mm_struct *mm,
        unsigned long long eaddr = start;
        unsigned long long eaddr_end = start + len;
        unsigned long current_asid, mm_asid;
-       unsigned long long flags;
+       unsigned long flags;
        unsigned long long epage_start;
 
        /*
@@ -342,7 +342,7 @@ static void inline sh64_dcache_purge_sets(int sets_to_purge_base, int n_sets)
                         * alloco is a NOP if the cache is write-through.
                         */
                        if (test_bit(SH_CACHE_MODE_WT, &(cpu_data->dcache.flags)))
-                               ctrl_inb(eaddr);
+                               __raw_readb((unsigned long)eaddr);
                }
        }
 
index 3edf297c829bd141ef7765f385eaf738fa0386db..ee8e6bbe882ca709b0fdfbf79e53b42c86a9be4a 100644 (file)
@@ -184,7 +184,6 @@ void __init paging_init(void)
 }
 
 static struct kcore_list kcore_mem, kcore_vmalloc;
-int after_bootmem = 0;
 
 void __init mem_init(void)
 {
@@ -217,8 +216,6 @@ void __init mem_init(void)
        memset(empty_zero_page, 0, PAGE_SIZE);
        __flush_wback_region(empty_zero_page, PAGE_SIZE);
 
-       after_bootmem = 1;
-
        codesize =  (unsigned long) &_etext - (unsigned long) &_text;
        datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
        initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
index 60cc486d2c2cc71f0f3b45df5b9bc4e856ae5a58..da2f4186f2cd32017418ede1205185cdd38d8897 100644 (file)
@@ -46,17 +46,15 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
                return NULL;
 
        /*
-        * If we're on an SH7751 or SH7780 PCI controller, PCI memory is
-        * mapped at the end of the address space (typically 0xfd000000)
-        * in a non-translatable area, so mapping through page tables for
-        * this area is not only pointless, but also fundamentally
-        * broken. Just return the physical address instead.
+        * If we're in the fixed PCI memory range, mapping through page
+        * tables is not only pointless, but also fundamentally broken.
+        * Just return the physical address instead.
         *
         * For boards that map a small PCI memory aperture somewhere in
         * P1/P2 space, ioremap() will already do the right thing,
         * and we'll never get this far.
         */
-       if (is_pci_memaddr(phys_addr) && is_pci_memaddr(last_addr))
+       if (is_pci_memory_fixed_range(phys_addr, size))
                return (void __iomem *)phys_addr;
 
 #if !defined(CONFIG_PMB_FIXED)
@@ -121,7 +119,9 @@ void __iounmap(void __iomem *addr)
        unsigned long seg = PXSEG(vaddr);
        struct vm_struct *p;
 
-       if (seg < P3SEG || vaddr >= P3_ADDR_MAX || is_pci_memaddr(vaddr))
+       if (seg < P3SEG || vaddr >= P3_ADDR_MAX)
+               return;
+       if (is_pci_memory_fixed_range(vaddr, 0))
                return;
 
 #ifdef CONFIG_PMB
index 31e1bb5effbeb0af274a6d4b2f6f21c74ed005d8..828c8597219da2b0e07fe9c73218b4d186521d92 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/io.h>
 #include <linux/bootmem.h>
 #include <linux/proc_fs.h>
+#include <linux/slab.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/addrspace.h>
 #include <asm/tlbflush.h>
 #include <asm/mmu.h>
 
-static void shmedia_mapioaddr(unsigned long, unsigned long);
-static unsigned long shmedia_ioremap(struct resource *, u32, int);
-
-/*
- * Generic mapping function (not visible outside):
- */
-
-/*
- * Remap an arbitrary physical address space into the kernel virtual
- * address space. Needed when the kernel wants to access high addresses
- * directly.
- *
- * NOTE! We need to allow non-page-aligned mappings too: we will obviously
- * have to convert them into an offset in a page-aligned mapping, but the
- * caller shouldn't need to know that small detail.
- */
-void *__ioremap(unsigned long phys_addr, unsigned long size,
-               unsigned long flags)
-{
-       void * addr;
-       struct vm_struct * area;
-       unsigned long offset, last_addr;
-       pgprot_t pgprot;
-
-       /* Don't allow wraparound or zero size */
-       last_addr = phys_addr + size - 1;
-       if (!size || last_addr < phys_addr)
-               return NULL;
-
-       pgprot = __pgprot(_PAGE_PRESENT  | _PAGE_READ   |
-                         _PAGE_WRITE    | _PAGE_DIRTY  |
-                         _PAGE_ACCESSED | _PAGE_SHARED | flags);
-
-       /*
-        * Mappings have to be page-aligned
-        */
-       offset = phys_addr & ~PAGE_MASK;
-       phys_addr &= PAGE_MASK;
-       size = PAGE_ALIGN(last_addr + 1) - phys_addr;
-
-       /*
-        * Ok, go for it..
-        */
-       area = get_vm_area(size, VM_IOREMAP);
-       if (!area)
-               return NULL;
-       pr_debug("Get vm_area returns %p addr %p\n", area, area->addr);
-       area->phys_addr = phys_addr;
-       addr = area->addr;
-       if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
-                              phys_addr, pgprot)) {
-               vunmap(addr);
-               return NULL;
-       }
-       return (void *) (offset + (char *)addr);
-}
-EXPORT_SYMBOL(__ioremap);
-
-void __iounmap(void *addr)
-{
-       struct vm_struct *area;
-
-       vfree((void *) (PAGE_MASK & (unsigned long) addr));
-       area = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr));
-       if (!area) {
-               printk(KERN_ERR "iounmap: bad address %p\n", addr);
-               return;
-       }
-
-       kfree(area);
-}
-EXPORT_SYMBOL(__iounmap);
-
 static struct resource shmedia_iomap = {
        .name   = "shmedia_iomap",
        .start  = IOBASE_VADDR + PAGE_SIZE,
        .end    = IOBASE_END - 1,
 };
 
-static void shmedia_mapioaddr(unsigned long pa, unsigned long va);
+static void shmedia_mapioaddr(unsigned long pa, unsigned long va,
+                             unsigned long flags);
 static void shmedia_unmapioaddr(unsigned long vaddr);
-static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz);
+static void __iomem *shmedia_ioremap(struct resource *res, u32 pa,
+                                    int sz, unsigned long flags);
 
 /*
  * We have the same problem as the SPARC, so lets have the same comment:
@@ -130,18 +60,18 @@ static struct xresource xresv[XNRES];
 
 static struct xresource *xres_alloc(void)
 {
-        struct xresource *xrp;
-        int n;
-
-        xrp = xresv;
-        for (n = 0; n < XNRES; n++) {
-                if (xrp->xflag == 0) {
-                        xrp->xflag = 1;
-                        return xrp;
-                }
-                xrp++;
-        }
-        return NULL;
+       struct xresource *xrp;
+       int n;
+
+       xrp = xresv;
+       for (n = 0; n < XNRES; n++) {
+               if (xrp->xflag == 0) {
+                       xrp->xflag = 1;
+                       return xrp;
+               }
+               xrp++;
+       }
+       return NULL;
 }
 
 static void xres_free(struct xresource *xrp)
@@ -161,76 +91,71 @@ static struct resource *shmedia_find_resource(struct resource *root,
        return NULL;
 }
 
-static unsigned long shmedia_alloc_io(unsigned long phys, unsigned long size,
-                                     const char *name)
+static void __iomem *shmedia_alloc_io(unsigned long phys, unsigned long size,
+                                     const char *name, unsigned long flags)
 {
-        static int printed_full = 0;
-        struct xresource *xres;
-        struct resource *res;
-        char *tack;
-        int tlen;
-
-        if (name == NULL) name = "???";
-
-        if ((xres = xres_alloc()) != 0) {
-                tack = xres->xname;
-                res = &xres->xres;
-        } else {
-                if (!printed_full) {
-                        printk("%s: done with statics, switching to kmalloc\n",
-                              __func__);
-                        printed_full = 1;
-                }
-                tlen = strlen(name);
-                tack = kmalloc(sizeof (struct resource) + tlen + 1, GFP_KERNEL);
-                if (!tack)
-                       return -ENOMEM;
-                memset(tack, 0, sizeof(struct resource));
-                res = (struct resource *) tack;
-                tack += sizeof (struct resource);
-        }
-
-        strncpy(tack, name, XNMLN);
-        tack[XNMLN] = 0;
-        res->name = tack;
-
-        return shmedia_ioremap(res, phys, size);
+       static int printed_full;
+       struct xresource *xres;
+       struct resource *res;
+       char *tack;
+       int tlen;
+
+       if (name == NULL)
+               name = "???";
+
+       xres = xres_alloc();
+       if (xres != 0) {
+               tack = xres->xname;
+               res = &xres->xres;
+       } else {
+               if (!printed_full) {
+                       printk(KERN_NOTICE "%s: done with statics, "
+                              "switching to kmalloc\n", __func__);
+                       printed_full = 1;
+               }
+               tlen = strlen(name);
+               tack = kmalloc(sizeof(struct resource) + tlen + 1, GFP_KERNEL);
+               if (!tack)
+                       return NULL;
+               memset(tack, 0, sizeof(struct resource));
+               res = (struct resource *) tack;
+               tack += sizeof(struct resource);
+       }
+
+       strncpy(tack, name, XNMLN);
+       tack[XNMLN] = 0;
+       res->name = tack;
+
+       return shmedia_ioremap(res, phys, size, flags);
 }
 
-static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz)
+static void __iomem *shmedia_ioremap(struct resource *res, u32 pa, int sz,
+                                    unsigned long flags)
 {
-        unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK);
+       unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK);
        unsigned long round_sz = (offset + sz + PAGE_SIZE-1) & PAGE_MASK;
-        unsigned long va;
-        unsigned int psz;
+       unsigned long va;
+       unsigned int psz;
 
-        if (allocate_resource(&shmedia_iomap, res, round_sz,
+       if (allocate_resource(&shmedia_iomap, res, round_sz,
                              shmedia_iomap.start, shmedia_iomap.end,
                              PAGE_SIZE, NULL, NULL) != 0) {
-                panic("alloc_io_res(%s): cannot occupy\n",
-                    (res->name != NULL)? res->name: "???");
-        }
+               panic("alloc_io_res(%s): cannot occupy\n",
+                     (res->name != NULL) ? res->name : "???");
+       }
 
-        va = res->start;
-        pa &= PAGE_MASK;
+       va = res->start;
+       pa &= PAGE_MASK;
 
        psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE;
 
-       /* log at boot time ... */
-       printk("mapioaddr: %6s  [%2d page%s]  va 0x%08lx   pa 0x%08x\n",
-              ((res->name != NULL) ? res->name : "???"),
-              psz, psz == 1 ? " " : "s", va, pa);
-
-        for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) {
-                shmedia_mapioaddr(pa, va);
-                va += PAGE_SIZE;
-                pa += PAGE_SIZE;
-        }
-
-        res->start += offset;
-        res->end = res->start + sz - 1;         /* not strictly necessary.. */
+       for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) {
+               shmedia_mapioaddr(pa, va, flags);
+               va += PAGE_SIZE;
+               pa += PAGE_SIZE;
+       }
 
-        return res->start;
+       return (void __iomem *)(unsigned long)(res->start + offset);
 }
 
 static void shmedia_free_io(struct resource *res)
@@ -249,14 +174,12 @@ static void shmedia_free_io(struct resource *res)
 
 static __init_refok void *sh64_get_page(void)
 {
-       extern int after_bootmem;
        void *page;
 
-       if (after_bootmem) {
-               page = (void *)get_zeroed_page(GFP_ATOMIC);
-       } else {
+       if (slab_is_available())
+               page = (void *)get_zeroed_page(GFP_KERNEL);
+       else
                page = alloc_bootmem_pages(PAGE_SIZE);
-       }
 
        if (!page || ((unsigned long)page & ~PAGE_MASK))
                panic("sh64_get_page: Out of memory already?\n");
@@ -264,17 +187,20 @@ static __init_refok void *sh64_get_page(void)
        return page;
 }
 
-static void shmedia_mapioaddr(unsigned long pa, unsigned long va)
+static void shmedia_mapioaddr(unsigned long pa, unsigned long va,
+                             unsigned long flags)
 {
        pgd_t *pgdp;
        pud_t *pudp;
        pmd_t *pmdp;
        pte_t *ptep, pte;
        pgprot_t prot;
-       unsigned long flags = 1; /* 1 = CB0-1 device */
 
        pr_debug("shmedia_mapiopage pa %08lx va %08lx\n",  pa, va);
 
+       if (!flags)
+               flags = 1; /* 1 = CB0-1 device */
+
        pgdp = pgd_offset_k(va);
        if (pgd_none(*pgdp) || !pgd_present(*pgdp)) {
                pudp = (pud_t *)sh64_get_page();
@@ -288,7 +214,7 @@ static void shmedia_mapioaddr(unsigned long pa, unsigned long va)
        }
 
        pmdp = pmd_offset(pudp, va);
-       if (pmd_none(*pmdp) || !pmd_present(*pmdp) ) {
+       if (pmd_none(*pmdp) || !pmd_present(*pmdp)) {
                ptep = (pte_t *)sh64_get_page();
                set_pmd(pmdp, __pmd((unsigned long)ptep + _PAGE_TABLE));
        }
@@ -336,17 +262,19 @@ static void shmedia_unmapioaddr(unsigned long vaddr)
        pte_clear(&init_mm, vaddr, ptep);
 }
 
-unsigned long onchip_remap(unsigned long phys, unsigned long size, const char *name)
+void __iomem *__ioremap(unsigned long offset, unsigned long size,
+                       unsigned long flags)
 {
-       if (size < PAGE_SIZE)
-               size = PAGE_SIZE;
+       char name[14];
 
-       return shmedia_alloc_io(phys, size, name);
+       sprintf(name, "phys_%08x", (u32)offset);
+       return shmedia_alloc_io(offset, size, name, flags);
 }
-EXPORT_SYMBOL(onchip_remap);
+EXPORT_SYMBOL(__ioremap);
 
-void onchip_unmap(unsigned long vaddr)
+void __iounmap(void __iomem *virtual)
 {
+       unsigned long vaddr = (unsigned long)virtual & PAGE_MASK;
        struct resource *res;
        unsigned int psz;
 
@@ -357,10 +285,7 @@ void onchip_unmap(unsigned long vaddr)
                return;
        }
 
-        psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE;
-
-        printk(KERN_DEBUG "unmapioaddr: %6s  [%2d page%s] freed\n",
-              res->name, psz, psz == 1 ? " " : "s");
+       psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE;
 
        shmedia_free_io(res);
 
@@ -371,9 +296,8 @@ void onchip_unmap(unsigned long vaddr)
                kfree(res);
        }
 }
-EXPORT_SYMBOL(onchip_unmap);
+EXPORT_SYMBOL(__iounmap);
 
-#ifdef CONFIG_PROC_FS
 static int
 ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof,
                  void *data)
@@ -385,7 +309,10 @@ ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof,
        for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) {
                if (p + 32 >= e)        /* Better than nothing */
                        break;
-               if ((nm = r->name) == 0) nm = "???";
+               nm = r->name;
+               if (nm == NULL)
+                       nm = "???";
+
                p += sprintf(p, "%08lx-%08lx: %s\n",
                             (unsigned long)r->start,
                             (unsigned long)r->end, nm);
@@ -393,14 +320,11 @@ ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof,
 
        return p-buf;
 }
-#endif /* CONFIG_PROC_FS */
 
 static int __init register_proc_onchip(void)
 {
-#ifdef CONFIG_PROC_FS
-       create_proc_read_entry("io_map",0,0, ioremap_proc_info, &shmedia_iomap);
-#endif
+       create_proc_read_entry("io_map", 0, 0, ioremap_proc_info,
+                              &shmedia_iomap);
        return 0;
 }
-
-__initcall(register_proc_onchip);
+late_initcall(register_proc_onchip);
index 931f4d003fa07fc66b2c4b9e14c53ac1e972c616..1b5fdfb4e0c2a98cb2a71b598e4d97ebc43bdd16 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/sh/mm/mmap.c
  *
- * Copyright (C) 2008  Paul Mundt
+ * Copyright (C) 2008 - 2009  Paul Mundt
  *
  * 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
@@ -21,9 +21,26 @@ EXPORT_SYMBOL(shm_align_mask);
 /*
  * To avoid cache aliases, we map the shared page with same color.
  */
-#define COLOUR_ALIGN(addr, pgoff)                              \
-       ((((addr) + shm_align_mask) & ~shm_align_mask) +        \
-        (((pgoff) << PAGE_SHIFT) & shm_align_mask))
+static inline unsigned long COLOUR_ALIGN(unsigned long addr,
+                                        unsigned long pgoff)
+{
+       unsigned long base = (addr + shm_align_mask) & ~shm_align_mask;
+       unsigned long off = (pgoff << PAGE_SHIFT) & shm_align_mask;
+
+       return base + off;
+}
+
+static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr,
+                                             unsigned long pgoff)
+{
+       unsigned long base = addr & ~shm_align_mask;
+       unsigned long off = (pgoff << PAGE_SHIFT) & shm_align_mask;
+
+       if (base + off <= addr)
+               return base + off;
+
+       return base - off;
+}
 
 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
        unsigned long len, unsigned long pgoff, unsigned long flags)
@@ -103,6 +120,117 @@ full_search:
                        addr = COLOUR_ALIGN(addr, pgoff);
        }
 }
+
+unsigned long
+arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
+                         const unsigned long len, const unsigned long pgoff,
+                         const unsigned long flags)
+{
+       struct vm_area_struct *vma;
+       struct mm_struct *mm = current->mm;
+       unsigned long addr = addr0;
+       int do_colour_align;
+
+       if (flags & MAP_FIXED) {
+               /* We do not accept a shared mapping if it would violate
+                * cache aliasing constraints.
+                */
+               if ((flags & MAP_SHARED) &&
+                   ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask))
+                       return -EINVAL;
+               return addr;
+       }
+
+       if (unlikely(len > TASK_SIZE))
+               return -ENOMEM;
+
+       do_colour_align = 0;
+       if (filp || (flags & MAP_SHARED))
+               do_colour_align = 1;
+
+       /* requesting a specific address */
+       if (addr) {
+               if (do_colour_align)
+                       addr = COLOUR_ALIGN(addr, pgoff);
+               else
+                       addr = PAGE_ALIGN(addr);
+
+               vma = find_vma(mm, addr);
+               if (TASK_SIZE - len >= addr &&
+                   (!vma || addr + len <= vma->vm_start))
+                       return addr;
+       }
+
+       /* check if free_area_cache is useful for us */
+       if (len <= mm->cached_hole_size) {
+               mm->cached_hole_size = 0;
+               mm->free_area_cache = mm->mmap_base;
+       }
+
+       /* either no address requested or can't fit in requested address hole */
+       addr = mm->free_area_cache;
+       if (do_colour_align) {
+               unsigned long base = COLOUR_ALIGN_DOWN(addr-len, pgoff);
+
+               addr = base + len;
+       }
+
+       /* make sure it can fit in the remaining address space */
+       if (likely(addr > len)) {
+               vma = find_vma(mm, addr-len);
+               if (!vma || addr <= vma->vm_start) {
+                       /* remember the address as a hint for next time */
+                       return (mm->free_area_cache = addr-len);
+               }
+       }
+
+       if (unlikely(mm->mmap_base < len))
+               goto bottomup;
+
+       addr = mm->mmap_base-len;
+       if (do_colour_align)
+               addr = COLOUR_ALIGN_DOWN(addr, pgoff);
+
+       do {
+               /*
+                * Lookup failure means no vma is above this address,
+                * else if new region fits below vma->vm_start,
+                * return with success:
+                */
+               vma = find_vma(mm, addr);
+               if (likely(!vma || addr+len <= vma->vm_start)) {
+                       /* remember the address as a hint for next time */
+                       return (mm->free_area_cache = addr);
+               }
+
+               /* remember the largest hole we saw so far */
+               if (addr + mm->cached_hole_size < vma->vm_start)
+                       mm->cached_hole_size = vma->vm_start - addr;
+
+               /* try just below the current vma->vm_start */
+               addr = vma->vm_start-len;
+               if (do_colour_align)
+                       addr = COLOUR_ALIGN_DOWN(addr, pgoff);
+       } while (likely(len < vma->vm_start));
+
+bottomup:
+       /*
+        * A failed mmap() very likely causes application failure,
+        * so fall back to the bottom-up function here. This scenario
+        * can happen with large stack limits and large mmap()
+        * allocations.
+        */
+       mm->cached_hole_size = ~0UL;
+       mm->free_area_cache = TASK_UNMAPPED_BASE;
+       addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
+       /*
+        * Restore the topdown base:
+        */
+       mm->free_area_cache = mm->mmap_base;
+       mm->cached_hole_size = ~0UL;
+
+       return addr;
+}
 #endif /* CONFIG_MMU */
 
 /*
index 1b9d4304b3bf796b4561aaffe201ff06ca3300d7..44f4e31c6d636b5d1fd1df7ded23df6d8c59d1db 100644 (file)
@@ -109,6 +109,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
        case CPU_SH7785:
        case CPU_SH7786:
        case CPU_SH7723:
+       case CPU_SH7724:
        case CPU_SHX3:
                lmodel = &op_model_sh4a_ops;
                break;
index 8477b5d884fd1147fa743e9f0bbba1767e672ff1..fec3a53b86504391375d200462825ae3d74cd132 100644 (file)
@@ -23,6 +23,7 @@ HD64461                       HD64461
 7619SE                 SH_7619_SOLUTION_ENGINE
 7721SE                 SH_7721_SOLUTION_ENGINE
 7722SE                 SH_7722_SOLUTION_ENGINE
+7724SE                 SH_7724_SOLUTION_ENGINE
 7751SE                 SH_7751_SOLUTION_ENGINE
 7780SE                 SH_7780_SOLUTION_ENGINE
 7751SYSTEMH            SH_7751_SYSTEMH
index 639ac805448ab500497270013b9176510849062a..65865726b28319238b16f109a032510a14b624e5 100644 (file)
@@ -102,8 +102,8 @@ struct thread_info {
 #define TI_KERN_CNTD1  0x00000488
 #define TI_PCR         0x00000490
 #define TI_RESTART_BLOCK 0x00000498
-#define TI_KUNA_REGS   0x000004c0
-#define TI_KUNA_INSN   0x000004c8
+#define TI_KUNA_REGS   0x000004c8
+#define TI_KUNA_INSN   0x000004d0
 #define TI_FPREGS      0x00000500
 
 /* We embed this in the uppermost byte of thread_info->flags */
index 5deabe921a47b6ebdcd5f6371faf7eaab3c135e4..e5e78f9cfc95d7104ede2ab767fdd1e5401f623c 100644 (file)
@@ -318,10 +318,12 @@ static void sun4u_irq_enable(unsigned int virt_irq)
        }
 }
 
-static void sun4u_set_affinity(unsigned int virt_irq,
+static int sun4u_set_affinity(unsigned int virt_irq,
                               const struct cpumask *mask)
 {
        sun4u_irq_enable(virt_irq);
+
+       return 0;
 }
 
 /* Don't do anything.  The desc->status check for IRQ_DISABLED in
@@ -377,7 +379,7 @@ static void sun4v_irq_enable(unsigned int virt_irq)
                       ino, err);
 }
 
-static void sun4v_set_affinity(unsigned int virt_irq,
+static int sun4v_set_affinity(unsigned int virt_irq,
                               const struct cpumask *mask)
 {
        unsigned int ino = virt_irq_table[virt_irq].dev_ino;
@@ -388,6 +390,8 @@ static void sun4v_set_affinity(unsigned int virt_irq,
        if (err != HV_EOK)
                printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
                       "err(%d)\n", ino, cpuid, err);
+
+       return 0;
 }
 
 static void sun4v_irq_disable(unsigned int virt_irq)
@@ -445,7 +449,7 @@ static void sun4v_virq_enable(unsigned int virt_irq)
                       dev_handle, dev_ino, err);
 }
 
-static void sun4v_virt_set_affinity(unsigned int virt_irq,
+static int sun4v_virt_set_affinity(unsigned int virt_irq,
                                    const struct cpumask *mask)
 {
        unsigned long cpuid, dev_handle, dev_ino;
@@ -461,6 +465,8 @@ static void sun4v_virt_set_affinity(unsigned int virt_irq,
                printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
                       "err(%d)\n",
                       dev_handle, dev_ino, cpuid, err);
+
+       return 0;
 }
 
 static void sun4v_virq_disable(unsigned int virt_irq)
index f934225fd8ef9c702c869c274df0c271c9a6a20b..aa9e926e13d73dca17015a5bd5f8e5eb76842c63 100644 (file)
@@ -451,23 +451,6 @@ static void do_ubd_request(struct request_queue * q);
 
 /* Only changed by ubd_init, which is an initcall. */
 static int thread_fd = -1;
-
-static void ubd_end_request(struct request *req, int bytes, int error)
-{
-       blk_end_request(req, error, bytes);
-}
-
-/* Callable only from interrupt context - otherwise you need to do
- * spin_lock_irq()/spin_lock_irqsave() */
-static inline void ubd_finish(struct request *req, int bytes)
-{
-       if(bytes < 0){
-               ubd_end_request(req, 0, -EIO);
-               return;
-       }
-       ubd_end_request(req, bytes, 0);
-}
-
 static LIST_HEAD(restart);
 
 /* XXX - move this inside ubd_intr. */
@@ -475,7 +458,6 @@ static LIST_HEAD(restart);
 static void ubd_handler(void)
 {
        struct io_thread_req *req;
-       struct request *rq;
        struct ubd *ubd;
        struct list_head *list, *next_ele;
        unsigned long flags;
@@ -492,10 +474,7 @@ static void ubd_handler(void)
                        return;
                }
 
-               rq = req->req;
-               rq->nr_sectors -= req->length >> 9;
-               if(rq->nr_sectors == 0)
-                       ubd_finish(rq, rq->hard_nr_sectors << 9);
+               blk_end_request(req->req, 0, req->length);
                kfree(req);
        }
        reactivate_fd(thread_fd, UBD_IRQ);
@@ -1243,27 +1222,26 @@ static void do_ubd_request(struct request_queue *q)
 {
        struct io_thread_req *io_req;
        struct request *req;
-       int n, last_sectors;
+       sector_t sector;
+       int n;
 
        while(1){
                struct ubd *dev = q->queuedata;
                if(dev->end_sg == 0){
-                       struct request *req = elv_next_request(q);
+                       struct request *req = blk_fetch_request(q);
                        if(req == NULL)
                                return;
 
                        dev->request = req;
-                       blkdev_dequeue_request(req);
                        dev->start_sg = 0;
                        dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
                }
 
                req = dev->request;
-               last_sectors = 0;
+               sector = blk_rq_pos(req);
                while(dev->start_sg < dev->end_sg){
                        struct scatterlist *sg = &dev->sg[dev->start_sg];
 
-                       req->sector += last_sectors;
                        io_req = kmalloc(sizeof(struct io_thread_req),
                                         GFP_ATOMIC);
                        if(io_req == NULL){
@@ -1272,10 +1250,10 @@ static void do_ubd_request(struct request_queue *q)
                                return;
                        }
                        prepare_request(req, io_req,
-                                       (unsigned long long) req->sector << 9,
+                                       (unsigned long long)sector << 9,
                                        sg->offset, sg->length, sg_page(sg));
 
-                       last_sectors = sg->length >> 9;
+                       sector += sg->length >> 9;
                        n = os_write_file(thread_fd, &io_req,
                                          sizeof(struct io_thread_req *));
                        if(n != sizeof(struct io_thread_req *)){
diff --git a/arch/x86/Kbuild b/arch/x86/Kbuild
new file mode 100644 (file)
index 0000000..ad8ec35
--- /dev/null
@@ -0,0 +1,16 @@
+
+obj-$(CONFIG_KVM) += kvm/
+
+# Xen paravirtualization support
+obj-$(CONFIG_XEN) += xen/
+
+# lguest paravirtualization support
+obj-$(CONFIG_LGUEST_GUEST) += lguest/
+
+obj-y += kernel/
+obj-y += mm/
+
+obj-y += crypto/
+obj-y += vdso/
+obj-$(CONFIG_IA32_EMULATION) += ia32/
+
index a6efe0a2e9ae613a81bedec5e4772698d16541cc..aafae3b140de40269abd0d9e02791853dc5cd1e6 100644 (file)
@@ -47,6 +47,11 @@ config X86
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_LZMA
 
+config OUTPUT_FORMAT
+       string
+       default "elf32-i386" if X86_32
+       default "elf64-x86-64" if X86_64
+
 config ARCH_DEFCONFIG
        string
        default "arch/x86/configs/i386_defconfig" if X86_32
@@ -274,15 +279,9 @@ config SPARSE_IRQ
 
          If you don't know what to do here, say N.
 
-config NUMA_MIGRATE_IRQ_DESC
-       bool "Move irq desc when changing irq smp_affinity"
+config NUMA_IRQ_DESC
+       def_bool y
        depends on SPARSE_IRQ && NUMA
-       depends on BROKEN
-       default n
-       ---help---
-         This enables moving irq_desc to cpu/node that irq will use handled.
-
-         If you don't know what to do here, say N.
 
 config X86_MPPARSE
        bool "Enable MPS table" if ACPI
@@ -355,7 +354,7 @@ config X86_UV
        depends on X86_64
        depends on X86_EXTENDED_PLATFORM
        depends on NUMA
-       select X86_X2APIC
+       depends on X86_X2APIC
        ---help---
          This option is needed in order to support SGI Ultraviolet systems.
          If you don't have one of these, you should say N here.
@@ -1466,9 +1465,7 @@ config KEXEC_JUMP
 
 config PHYSICAL_START
        hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
-       default "0x1000000" if X86_NUMAQ
-       default "0x200000" if X86_64
-       default "0x100000"
+       default "0x1000000"
        ---help---
          This gives the physical address where the kernel is loaded.
 
@@ -1487,15 +1484,15 @@ config PHYSICAL_START
          to be specifically compiled to run from a specific memory area
          (normally a reserved region) and this option comes handy.
 
-         So if you are using bzImage for capturing the crash dump, leave
-         the value here unchanged to 0x100000 and set CONFIG_RELOCATABLE=y.
-         Otherwise if you plan to use vmlinux for capturing the crash dump
-         change this value to start of the reserved region (Typically 16MB
-         0x1000000). In other words, it can be set based on the "X" value as
-         specified in the "crashkernel=YM@XM" command line boot parameter
-         passed to the panic-ed kernel. Typically this parameter is set as
-         crashkernel=64M@16M. Please take a look at
-         Documentation/kdump/kdump.txt for more details about crash dumps.
+         So if you are using bzImage for capturing the crash dump,
+         leave the value here unchanged to 0x1000000 and set
+         CONFIG_RELOCATABLE=y.  Otherwise if you plan to use vmlinux
+         for capturing the crash dump change this value to start of
+         the reserved region.  In other words, it can be set based on
+         the "X" value as specified in the "crashkernel=YM@XM"
+         command line boot parameter passed to the panic-ed
+         kernel. Please take a look at Documentation/kdump/kdump.txt
+         for more details about crash dumps.
 
          Usage of bzImage for capturing the crash dump is recommended as
          one does not have to build two kernels. Same kernel can be used
@@ -1508,8 +1505,8 @@ config PHYSICAL_START
          Don't change this unless you know what you are doing.
 
 config RELOCATABLE
-       bool "Build a relocatable kernel (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
+       bool "Build a relocatable kernel"
+       default y
        ---help---
          This builds a kernel image that retains relocation information
          so it can be loaded someplace besides the default 1MB.
@@ -1524,12 +1521,16 @@ config RELOCATABLE
          it has been loaded at and the compile time physical address
          (CONFIG_PHYSICAL_START) is ignored.
 
+# Relocation on x86-32 needs some additional build support
+config X86_NEED_RELOCS
+       def_bool y
+       depends on X86_32 && RELOCATABLE
+
 config PHYSICAL_ALIGN
        hex
        prompt "Alignment value to which kernel should be aligned" if X86_32
-       default "0x100000" if X86_32
-       default "0x200000" if X86_64
-       range 0x2000 0x400000
+       default "0x1000000"
+       range 0x2000 0x1000000
        ---help---
          This value puts the alignment restrictions on physical address
          where kernel is loaded and run from. Kernel is compiled for an
index d8359e73317f8dfb8b929f15f555f5593469e7fd..d105f29bb6bb7c9b75fe3369d66f68f2f3ada5ba 100644 (file)
@@ -159,14 +159,30 @@ config IOMMU_DEBUG
          options. See Documentation/x86_64/boot-options.txt for more
          details.
 
+config IOMMU_STRESS
+       bool "Enable IOMMU stress-test mode"
+       ---help---
+         This option disables various optimizations in IOMMU related
+         code to do real stress testing of the IOMMU code. This option
+         will cause a performance drop and should only be enabled for
+         testing.
+
 config IOMMU_LEAK
        bool "IOMMU leak tracing"
-       depends on DEBUG_KERNEL
-       depends on IOMMU_DEBUG
+       depends on IOMMU_DEBUG && DMA_API_DEBUG
        ---help---
          Add a simple leak tracer to the IOMMU code. This is useful when you
          are debugging a buggy device driver that leaks IOMMU mappings.
 
+config X86_DS_SELFTEST
+    bool "DS selftest"
+    default y
+    depends on DEBUG_KERNEL
+    depends on X86_DS
+       ---help---
+         Perform Debug Store selftests at boot time.
+         If in doubt, say "N".
+
 config HAVE_MMIOTRACE_SUPPORT
        def_bool y
 
index 8c86b72afdc2d39bc8957692e35335ebabae82bc..edbd0ca620678fd6627c60d4849a07852a823b11 100644 (file)
@@ -7,8 +7,6 @@ else
         KBUILD_DEFCONFIG := $(ARCH)_defconfig
 endif
 
-core-$(CONFIG_KVM) += arch/x86/kvm/
-
 # BITS is used as extension for files which are available in a 32 bit
 # and a 64 bit version to simplify shared Makefiles.
 # e.g.: obj-y += foo_$(BITS).o
@@ -118,21 +116,8 @@ head-y += arch/x86/kernel/init_task.o
 
 libs-y  += arch/x86/lib/
 
-# Sub architecture files that needs linking first
-core-y += $(fcore-y)
-
-# Xen paravirtualization support
-core-$(CONFIG_XEN) += arch/x86/xen/
-
-# lguest paravirtualization support
-core-$(CONFIG_LGUEST_GUEST) += arch/x86/lguest/
-
-core-y += arch/x86/kernel/
-core-y += arch/x86/mm/
-
-core-y += arch/x86/crypto/
-core-y += arch/x86/vdso/
-core-$(CONFIG_IA32_EMULATION) += arch/x86/ia32/
+# See arch/x86/Kbuild for content of core part of the kernel
+core-y += arch/x86/
 
 # drivers-y are linked after core-y
 drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/
index 172cf8a98bdd2541e0d930e2a92903f5f8f9d448..851fe936d2421a14d7a558e2946321503d73a5b6 100644 (file)
@@ -3,6 +3,8 @@ bzImage
 cpustr.h
 mkcpustr
 offsets.h
+voffset.h
+zoffset.h
 setup
 setup.bin
 setup.elf
index 6633b6e7505a68cc32ebc198f9ec6cd46cd0d9c3..8d16ada250480cb57168ea8b600c920f7c1f5192 100644 (file)
@@ -26,9 +26,10 @@ targets              := vmlinux.bin setup.bin setup.elf bzImage
 targets                += fdimage fdimage144 fdimage288 image.iso mtools.conf
 subdir-                := compressed
 
-setup-y                += a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o
+setup-y                += a20.o bioscall.o cmdline.o copy.o cpu.o cpucheck.o edd.o
 setup-y                += header.o main.o mca.o memory.o pm.o pmjump.o
-setup-y                += printf.o string.o tty.o video.o video-mode.o version.o
+setup-y                += printf.o regs.o string.o tty.o video.o video-mode.o
+setup-y                += version.o
 setup-$(CONFIG_X86_APM_BOOT) += apm.o
 
 # The link order of the video-*.o modules can matter.  In particular,
@@ -86,19 +87,27 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
 
 SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
 
-sed-offsets := -e 's/^00*/0/' \
-        -e 's/^\([0-9a-fA-F]*\) . \(input_data\|input_data_end\)$$/\#define \2 0x\1/p'
+sed-voffset := -e 's/^\([0-9a-fA-F]*\) . \(_text\|_end\)$$/\#define VO_\2 0x\1/p'
 
-quiet_cmd_offsets = OFFSETS $@
-      cmd_offsets = $(NM) $< | sed -n $(sed-offsets) > $@
+quiet_cmd_voffset = VOFFSET $@
+      cmd_voffset = $(NM) $< | sed -n $(sed-voffset) > $@
 
-$(obj)/offsets.h: $(obj)/compressed/vmlinux FORCE
-       $(call if_changed,offsets)
+targets += voffset.h
+$(obj)/voffset.h: vmlinux FORCE
+       $(call if_changed,voffset)
+
+sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p'
+
+quiet_cmd_zoffset = ZOFFSET $@
+      cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
+
+targets += zoffset.h
+$(obj)/zoffset.h: $(obj)/compressed/vmlinux FORCE
+       $(call if_changed,zoffset)
 
-targets += offsets.h
 
 AFLAGS_header.o += -I$(obj)
-$(obj)/header.o: $(obj)/offsets.h
+$(obj)/header.o: $(obj)/voffset.h $(obj)/zoffset.h
 
 LDFLAGS_setup.elf      := -T
 $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
index 7c19ce8c2442c219a1e85ee22798a8abaa0bdf2c..64a31a6d751a0132b9b09ea71da1b31b5ec955d8 100644 (file)
@@ -2,7 +2,7 @@
  *
  *   Copyright (C) 1991, 1992 Linus Torvalds
  *   Copyright 2007-2008 rPath, Inc. - All Rights Reserved
- *   Copyright 2009 Intel Corporation
+ *   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.
@@ -90,8 +90,11 @@ static int a20_test_long(void)
 
 static void enable_a20_bios(void)
 {
-       asm volatile("pushfl; int $0x15; popfl"
-                    : : "a" ((u16)0x2401));
+       struct biosregs ireg;
+
+       initregs(&ireg);
+       ireg.ax = 0x2401;
+       intcall(0x15, &ireg, NULL);
 }
 
 static void enable_a20_kbc(void)
index 7aa6033001f9ace30ef1a4ffdb52bfd629a98f26..ee274834ea8ba35cf0a804d8be7cf07fa0077993 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
  *
  *   Original APM BIOS checking by Stephen Rothwell, May 1994
  *   (sfr@canb.auug.org.au)
 
 int query_apm_bios(void)
 {
-       u16 ax, bx, cx, dx, di;
-       u32 ebx, esi;
-       u8 err;
+       struct biosregs ireg, oreg;
 
        /* APM BIOS installation check */
-       ax = 0x5300;
-       bx = cx = 0;
-       asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0"
-                    : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx)
-                    : : "esi", "edi");
+       initregs(&ireg);
+       ireg.ah = 0x53;
+       intcall(0x15, &ireg, &oreg);
 
-       if (err)
+       if (oreg.flags & X86_EFLAGS_CF)
                return -1;              /* No APM BIOS */
 
-       if (bx != 0x504d)       /* "PM" signature */
+       if (oreg.bx != 0x504d)          /* "PM" signature */
                return -1;
 
-       if (!(cx & 0x02))               /* 32 bits supported? */
+       if (!(oreg.cx & 0x02))          /* 32 bits supported? */
                return -1;
 
        /* Disconnect first, just in case */
-       ax = 0x5304;
-       bx = 0;
-       asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp"
-                    : "+a" (ax), "+b" (bx)
-                    : : "ecx", "edx", "esi", "edi");
-
-       /* Paranoia */
-       ebx = esi = 0;
-       cx = dx = di = 0;
+       ireg.al = 0x04;
+       intcall(0x15, &ireg, NULL);
 
        /* 32-bit connect */
-       asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %6"
-                    : "=a" (ax), "+b" (ebx), "+c" (cx), "+d" (dx),
-                      "+S" (esi), "+D" (di), "=m" (err)
-                    : "a" (0x5303));
-
-       boot_params.apm_bios_info.cseg = ax;
-       boot_params.apm_bios_info.offset = ebx;
-       boot_params.apm_bios_info.cseg_16 = cx;
-       boot_params.apm_bios_info.dseg = dx;
-       boot_params.apm_bios_info.cseg_len = (u16)esi;
-       boot_params.apm_bios_info.cseg_16_len = esi >> 16;
-       boot_params.apm_bios_info.dseg_len = di;
-
-       if (err)
+       ireg.al = 0x03;
+       intcall(0x15, &ireg, &oreg);
+
+       boot_params.apm_bios_info.cseg        = oreg.ax;
+       boot_params.apm_bios_info.offset      = oreg.ebx;
+       boot_params.apm_bios_info.cseg_16     = oreg.cx;
+       boot_params.apm_bios_info.dseg        = oreg.dx;
+       boot_params.apm_bios_info.cseg_len    = oreg.si;
+       boot_params.apm_bios_info.cseg_16_len = oreg.hsi;
+       boot_params.apm_bios_info.dseg_len    = oreg.di;
+
+       if (oreg.flags & X86_EFLAGS_CF)
                return -1;
 
        /* Redo the installation check as the 32-bit connect;
           some BIOSes return different flags this way... */
 
-       ax = 0x5300;
-       bx = cx = 0;
-       asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0"
-                    : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx)
-                    : : "esi", "edi");
+       ireg.al = 0x00;
+       intcall(0x15, &ireg, &oreg);
 
-       if (err || bx != 0x504d) {
+       if ((oreg.eflags & X86_EFLAGS_CF) || oreg.bx != 0x504d) {
                /* Failure with 32-bit connect, try to disconect and ignore */
-               ax = 0x5304;
-               bx = 0;
-               asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp"
-                            : "+a" (ax), "+b" (bx)
-                            : : "ecx", "edx", "esi", "edi");
+               ireg.al = 0x04;
+               intcall(0x15, &ireg, NULL);
                return -1;
        }
 
-       boot_params.apm_bios_info.version = ax;
-       boot_params.apm_bios_info.flags cx;
+       boot_params.apm_bios_info.version = oreg.ax;
+       boot_params.apm_bios_info.flags   = oreg.cx;
        return 0;
 }
 
diff --git a/arch/x86/boot/bioscall.S b/arch/x86/boot/bioscall.S
new file mode 100644 (file)
index 0000000..5077937
--- /dev/null
@@ -0,0 +1,82 @@
+/* -----------------------------------------------------------------------
+ *
+ *   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 or (at your
+ *   option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * "Glove box" for BIOS calls.  Avoids the constant problems with BIOSes
+ * touching registers they shouldn't be.
+ */
+
+       .code16
+       .text
+       .globl  intcall
+       .type   intcall, @function
+intcall:
+       /* Self-modify the INT instruction.  Ugly, but works. */
+       cmpb    %al, 3f
+       je      1f
+       movb    %al, 3f
+       jmp     1f              /* Synchronize pipeline */
+1:
+       /* Save state */
+       pushfl
+       pushw   %fs
+       pushw   %gs
+       pushal
+
+       /* Copy input state to stack frame */
+       subw    $44, %sp
+       movw    %dx, %si
+       movw    %sp, %di
+       movw    $11, %cx
+       rep; movsd
+
+       /* Pop full state from the stack */
+       popal
+       popw    %gs
+       popw    %fs
+       popw    %es
+       popw    %ds
+       popfl
+
+       /* Actual INT */
+       .byte   0xcd            /* INT opcode */
+3:     .byte   0
+
+       /* Push full state to the stack */
+       pushfl
+       pushw   %ds
+       pushw   %es
+       pushw   %fs
+       pushw   %gs
+       pushal
+
+       /* Re-establish C environment invariants */
+       cld
+       movzwl  %sp, %esp
+       movw    %cs, %ax
+       movw    %ax, %ds
+       movw    %ax, %es
+
+       /* Copy output state from stack frame */
+       movw    68(%esp), %di   /* Original %cx == 3rd argument */
+       andw    %di, %di
+       jz      4f
+       movw    %sp, %si
+       movw    $11, %cx
+       rep; movsd
+4:     addw    $44, %sp
+
+       /* Restore state and return */
+       popal
+       popw    %gs
+       popw    %fs
+       popfl
+       retl
+       .size   intcall, .-intcall
index 7b2692e897e5fcd75f53073dcf543665d838eb6b..98239d2658f27b3ed3494ea1b0ad3d6cd0a01624 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.
@@ -26,6 +27,7 @@
 #include <asm/setup.h>
 #include "bitops.h"
 #include <asm/cpufeature.h>
+#include <asm/processor-flags.h>
 
 /* Useful macros */
 #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
@@ -241,6 +243,49 @@ int enable_a20(void);
 /* apm.c */
 int query_apm_bios(void);
 
+/* bioscall.c */
+struct biosregs {
+       union {
+               struct {
+                       u32 edi;
+                       u32 esi;
+                       u32 ebp;
+                       u32 _esp;
+                       u32 ebx;
+                       u32 edx;
+                       u32 ecx;
+                       u32 eax;
+                       u32 _fsgs;
+                       u32 _dses;
+                       u32 eflags;
+               };
+               struct {
+                       u16 di, hdi;
+                       u16 si, hsi;
+                       u16 bp, hbp;
+                       u16 _sp, _hsp;
+                       u16 bx, hbx;
+                       u16 dx, hdx;
+                       u16 cx, hcx;
+                       u16 ax, hax;
+                       u16 gs, fs;
+                       u16 es, ds;
+                       u16 flags, hflags;
+               };
+               struct {
+                       u8 dil, dih, edi2, edi3;
+                       u8 sil, sih, esi2, esi3;
+                       u8 bpl, bph, ebp2, ebp3;
+                       u8 _spl, _sph, _esp2, _esp3;
+                       u8 bl, bh, ebx2, ebx3;
+                       u8 dl, dh, edx2, edx3;
+                       u8 cl, ch, ecx2, ecx3;
+                       u8 al, ah, eax2, eax3;
+               };
+       };
+};
+void intcall(u8 int_no, const struct biosregs *ireg, struct biosregs *oreg);
+
 /* cmdline.c */
 int cmdline_find_option(const char *option, char *buffer, int bufsize);
 int cmdline_find_option_bool(const char *option);
@@ -279,6 +324,9 @@ int sprintf(char *buf, const char *fmt, ...);
 int vsprintf(char *buf, const char *fmt, va_list args);
 int printf(const char *fmt, ...);
 
+/* regs.c */
+void initregs(struct biosregs *regs);
+
 /* string.c */
 int strcmp(const char *str1, const char *str2);
 size_t strnlen(const char *s, size_t maxlen);
index 63eff3b04d0181be4eb6163522989760d82e23b7..4a46fab7162e3b753d143eaedbbf1dcaabf8822d 100644 (file)
@@ -1,3 +1,6 @@
 relocs
 vmlinux.bin.all
 vmlinux.relocs
+vmlinux.lds
+mkpiggy
+piggy.S
index 65551c9f85718baf762d203329b6be42082a2b9c..49c8a4c37d7c3b29bc7f5fb4d0ea660aec6fdf11 100644 (file)
@@ -19,7 +19,9 @@ KBUILD_AFLAGS  := $(KBUILD_CFLAGS) -D__ASSEMBLY__
 LDFLAGS := -m elf_$(UTS_MACHINE)
 LDFLAGS_vmlinux := -T
 
-$(obj)/vmlinux: $(src)/vmlinux_$(BITS).lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/piggy.o FORCE
+hostprogs-y    := mkpiggy
+
+$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/piggy.o FORCE
        $(call if_changed,ld)
        @:
 
@@ -29,7 +31,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
 
 
 targets += vmlinux.bin.all vmlinux.relocs relocs
-hostprogs-$(CONFIG_X86_32) += relocs
+hostprogs-$(CONFIG_X86_NEED_RELOCS) += relocs
 
 quiet_cmd_relocs = RELOCS  $@
       cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $<
@@ -37,46 +39,22 @@ $(obj)/vmlinux.relocs: vmlinux $(obj)/relocs FORCE
        $(call if_changed,relocs)
 
 vmlinux.bin.all-y := $(obj)/vmlinux.bin
-vmlinux.bin.all-$(CONFIG_RELOCATABLE) += $(obj)/vmlinux.relocs
-quiet_cmd_relocbin = BUILD   $@
-      cmd_relocbin = cat $(filter-out FORCE,$^) > $@
-$(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE
-       $(call if_changed,relocbin)
-
-ifeq ($(CONFIG_X86_32),y)
+vmlinux.bin.all-$(CONFIG_X86_NEED_RELOCS) += $(obj)/vmlinux.relocs
 
-ifdef CONFIG_RELOCATABLE
-$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE
-       $(call if_changed,gzip)
-$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin.all FORCE
-       $(call if_changed,bzip2)
-$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin.all FORCE
-       $(call if_changed,lzma)
-else
-$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,gzip)
-$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
+$(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,bzip2)
-$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
+$(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,lzma)
-endif
-LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T
 
-else
+suffix-$(CONFIG_KERNEL_GZIP)   := gz
+suffix-$(CONFIG_KERNEL_BZIP2)  := bz2
+suffix-$(CONFIG_KERNEL_LZMA)   := lzma
 
-$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
-       $(call if_changed,gzip)
-$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
-       $(call if_changed,bzip2)
-$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
-       $(call if_changed,lzma)
-
-LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T
-endif
+quiet_cmd_mkpiggy = MKPIGGY $@
+      cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false )
 
-suffix_$(CONFIG_KERNEL_GZIP)  = gz
-suffix_$(CONFIG_KERNEL_BZIP2) = bz2
-suffix_$(CONFIG_KERNEL_LZMA)  = lzma
-
-$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix_y) FORCE
-       $(call if_changed,ld)
+targets += piggy.S
+$(obj)/piggy.S: $(obj)/vmlinux.bin.$(suffix-y) $(obj)/mkpiggy FORCE
+       $(call if_changed,mkpiggy)
index 3a8a866fb2e291e958478cb741a56d16b1016e5f..75e4f001e7061e5d3036197ac202dbee8e3d07a2 100644 (file)
  * the page directory. [According to comments etc elsewhere on a compressed
  * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
  *
- * Page 0 is deliberately kept safe, since System Management Mode code in 
+ * Page 0 is deliberately kept safe, since System Management Mode code in
  * laptops may need to access the BIOS data stored there.  This is also
- * useful for future device drivers that either access the BIOS via VM86 
+ * useful for future device drivers that either access the BIOS via VM86
  * mode.
  */
 
 /*
  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  */
-.text
+       .text
 
 #include <linux/linkage.h>
 #include <asm/segment.h>
 #include <asm/boot.h>
 #include <asm/asm-offsets.h>
 
-.section ".text.head","ax",@progbits
+       .section ".text.head","ax",@progbits
 ENTRY(startup_32)
        cld
-       /* test KEEP_SEGMENTS flag to see if the bootloader is asking
-        * us to not reload segments */
-       testb $(1<<6), BP_loadflags(%esi)
-       jnz 1f
+       /*
+        * Test KEEP_SEGMENTS flag to see if the bootloader is asking
+        * us to not reload segments
+        */
+       testb   $(1<<6), BP_loadflags(%esi)
+       jnz     1f
 
        cli
-       movl $(__BOOT_DS),%eax
-       movl %eax,%ds
-       movl %eax,%es
-       movl %eax,%fs
-       movl %eax,%gs
-       movl %eax,%ss
+       movl    $__BOOT_DS, %eax
+       movl    %eax, %ds
+       movl    %eax, %es
+       movl    %eax, %fs
+       movl    %eax, %gs
+       movl    %eax, %ss
 1:
 
-/* Calculate the delta between where we were compiled to run
+/*
+ * Calculate the delta between where we were compiled to run
  * at and where we were actually loaded at.  This can only be done
  * with a short local call on x86.  Nothing  else will tell us what
  * address we are running at.  The reserved chunk of the real-mode
  * data at 0x1e4 (defined as a scratch field) are used as the stack
  * for this calculation. Only 4 bytes are needed.
  */
-       leal (0x1e4+4)(%esi), %esp
-       call 1f
-1:     popl %ebp
-       subl $1b, %ebp
+       leal    (BP_scratch+4)(%esi), %esp
+       call    1f
+1:     popl    %ebp
+       subl    $1b, %ebp
 
-/* %ebp contains the address we are loaded at by the boot loader and %ebx
+/*
+ * %ebp contains the address we are loaded at by the boot loader and %ebx
  * contains the address where we should move the kernel image temporarily
  * for safe in-place decompression.
  */
 
 #ifdef CONFIG_RELOCATABLE
-       movl    %ebp, %ebx
-       addl    $(CONFIG_PHYSICAL_ALIGN - 1), %ebx
-       andl    $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebx
+       movl    %ebp, %ebx
+       movl    BP_kernel_alignment(%esi), %eax
+       decl    %eax
+       addl    %eax, %ebx
+       notl    %eax
+       andl    %eax, %ebx
 #else
-       movl $LOAD_PHYSICAL_ADDR, %ebx
+       movl    $LOAD_PHYSICAL_ADDR, %ebx
 #endif
 
-       /* Replace the compressed data size with the uncompressed size */
-       subl input_len(%ebp), %ebx
-       movl output_len(%ebp), %eax
-       addl %eax, %ebx
-       /* Add 8 bytes for every 32K input block */
-       shrl $12, %eax
-       addl %eax, %ebx
-       /* Add 32K + 18 bytes of extra slack */
-       addl $(32768 + 18), %ebx
-       /* Align on a 4K boundary */
-       addl $4095, %ebx
-       andl $~4095, %ebx
-
-/* Copy the compressed kernel to the end of our buffer
+       /* Target address to relocate to for decompression */
+       addl    $z_extract_offset, %ebx
+
+       /* Set up the stack */
+       leal    boot_stack_end(%ebx), %esp
+
+       /* Zero EFLAGS */
+       pushl   $0
+       popfl
+
+/*
+ * Copy the compressed kernel to the end of our buffer
  * where decompression in place becomes safe.
  */
-       pushl %esi
-       leal _end(%ebp), %esi
-       leal _end(%ebx), %edi
-       movl $(_end - startup_32), %ecx
+       pushl   %esi
+       leal    (_bss-4)(%ebp), %esi
+       leal    (_bss-4)(%ebx), %edi
+       movl    $(_bss - startup_32), %ecx
+       shrl    $2, %ecx
        std
-       rep
-       movsb
+       rep     movsl
        cld
-       popl %esi
-
-/* Compute the kernel start address.
- */
-#ifdef CONFIG_RELOCATABLE
-       addl    $(CONFIG_PHYSICAL_ALIGN - 1), %ebp
-       andl    $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebp
-#else
-       movl    $LOAD_PHYSICAL_ADDR, %ebp
-#endif
+       popl    %esi
 
 /*
  * Jump to the relocated address.
  */
-       leal relocated(%ebx), %eax
-       jmp *%eax
+       leal    relocated(%ebx), %eax
+       jmp     *%eax
 ENDPROC(startup_32)
 
-.section ".text"
+       .text
 relocated:
 
 /*
- * Clear BSS
- */
-       xorl %eax,%eax
-       leal _edata(%ebx),%edi
-       leal _end(%ebx), %ecx
-       subl %edi,%ecx
-       cld
-       rep
-       stosb
-
-/*
- * Setup the stack for the decompressor
+ * Clear BSS (stack is currently empty)
  */
-       leal boot_stack_end(%ebx), %esp
+       xorl    %eax, %eax
+       leal    _bss(%ebx), %edi
+       leal    _ebss(%ebx), %ecx
+       subl    %edi, %ecx
+       shrl    $2, %ecx
+       rep     stosl
 
 /*
  * Do the decompression, and jump to the new kernel..
  */
-       movl output_len(%ebx), %eax
-       pushl %eax
-                       # push arguments for decompress_kernel:
-       pushl %ebp      # output address
-       movl input_len(%ebx), %eax
-       pushl %eax      # input_len
-       leal input_data(%ebx), %eax
-       pushl %eax      # input_data
-       leal boot_heap(%ebx), %eax
-       pushl %eax      # heap area
-       pushl %esi      # real mode pointer
-       call decompress_kernel
-       addl $20, %esp
-       popl %ecx
+       leal    z_extract_offset_negative(%ebx), %ebp
+                               /* push arguments for decompress_kernel: */
+       pushl   %ebp            /* output address */
+       pushl   $z_input_len    /* input_len */
+       leal    input_data(%ebx), %eax
+       pushl   %eax            /* input_data */
+       leal    boot_heap(%ebx), %eax
+       pushl   %eax            /* heap area */
+       pushl   %esi            /* real mode pointer */
+       call    decompress_kernel
+       addl    $20, %esp
 
 #if CONFIG_RELOCATABLE
-/* Find the address of the relocations.
+/*
+ * Find the address of the relocations.
  */
-       movl %ebp, %edi
-       addl %ecx, %edi
+       leal    z_output_len(%ebp), %edi
 
-/* Calculate the delta between where vmlinux was compiled to run
+/*
+ * Calculate the delta between where vmlinux was compiled to run
  * and where it was actually loaded.
  */
-       movl %ebp, %ebx
-       subl $LOAD_PHYSICAL_ADDR, %ebx
-       jz   2f         /* Nothing to be done if loaded at compiled addr. */
+       movl    %ebp, %ebx
+       subl    $LOAD_PHYSICAL_ADDR, %ebx
+       jz      2f      /* Nothing to be done if loaded at compiled addr. */
 /*
  * Process relocations.
  */
 
-1:     subl $4, %edi
-       movl 0(%edi), %ecx
-       testl %ecx, %ecx
-       jz 2f
-       addl %ebx, -__PAGE_OFFSET(%ebx, %ecx)
-       jmp 1b
+1:     subl    $4, %edi
+       movl    (%edi), %ecx
+       testl   %ecx, %ecx
+       jz      2f
+       addl    %ebx, -__PAGE_OFFSET(%ebx, %ecx)
+       jmp     1b
 2:
 #endif
 
 /*
  * Jump to the decompressed kernel.
  */
-       xorl %ebx,%ebx
-       jmp *%ebp
+       xorl    %ebx, %ebx
+       jmp     *%ebp
 
-.bss
-/* Stack and heap for uncompression */
-.balign 4
+/*
+ * Stack and heap for uncompression
+ */
+       .bss
+       .balign 4
 boot_heap:
        .fill BOOT_HEAP_SIZE, 1, 0
 boot_stack:
index ed4a8294800268c25667b5ede9bc42e2cdd229c9..f62c284db9eb5c94edf1df794b26e13ace0b4113 100644 (file)
@@ -21,8 +21,8 @@
 /*
  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  */
-.code32
-.text
+       .code32
+       .text
 
 #include <linux/linkage.h>
 #include <asm/segment.h>
 #include <asm/processor-flags.h>
 #include <asm/asm-offsets.h>
 
-.section ".text.head"
+       .section ".text.head"
        .code32
 ENTRY(startup_32)
        cld
-       /* test KEEP_SEGMENTS flag to see if the bootloader is asking
-        * us to not reload segments */
+       /*
+        * Test KEEP_SEGMENTS flag to see if the bootloader is asking
+        * us to not reload segments
+        */
        testb $(1<<6), BP_loadflags(%esi)
        jnz 1f
 
@@ -49,14 +51,15 @@ ENTRY(startup_32)
        movl    %eax, %ss
 1:
 
-/* Calculate the delta between where we were compiled to run
+/*
+ * Calculate the delta between where we were compiled to run
  * at and where we were actually loaded at.  This can only be done
  * with a short local call on x86.  Nothing  else will tell us what
  * address we are running at.  The reserved chunk of the real-mode
  * data at 0x1e4 (defined as a scratch field) are used as the stack
  * for this calculation. Only 4 bytes are needed.
  */
-       leal    (0x1e4+4)(%esi), %esp
+       leal    (BP_scratch+4)(%esi), %esp
        call    1f
 1:     popl    %ebp
        subl    $1b, %ebp
@@ -70,32 +73,28 @@ ENTRY(startup_32)
        testl   %eax, %eax
        jnz     no_longmode
 
-/* Compute the delta between where we were compiled to run at
+/*
+ * Compute the delta between where we were compiled to run at
  * and where the code will actually run at.
- */
-/* %ebp contains the address we are loaded at by the boot loader and %ebx
+ *
+ * %ebp contains the address we are loaded at by the boot loader and %ebx
  * contains the address where we should move the kernel image temporarily
  * for safe in-place decompression.
  */
 
 #ifdef CONFIG_RELOCATABLE
        movl    %ebp, %ebx
-       addl    $(PMD_PAGE_SIZE -1), %ebx
-       andl    $PMD_PAGE_MASK, %ebx
+       movl    BP_kernel_alignment(%esi), %eax
+       decl    %eax
+       addl    %eax, %ebx
+       notl    %eax
+       andl    %eax, %ebx
 #else
-       movl    $CONFIG_PHYSICAL_START, %ebx
+       movl    $LOAD_PHYSICAL_ADDR, %ebx
 #endif
 
-       /* Replace the compressed data size with the uncompressed size */
-       subl    input_len(%ebp), %ebx
-       movl    output_len(%ebp), %eax
-       addl    %eax, %ebx
-       /* Add 8 bytes for every 32K input block */
-       shrl    $12, %eax
-       addl    %eax, %ebx
-       /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */
-       addl    $(32768 + 18 + 4095), %ebx
-       andl    $~4095, %ebx
+       /* Target address to relocate to for decompression */
+       addl    $z_extract_offset, %ebx
 
 /*
  * Prepare for entering 64 bit mode
@@ -114,7 +113,7 @@ ENTRY(startup_32)
  /*
   * Build early 4G boot pagetable
   */
-       /* Initialize Page tables to 0*/
+       /* Initialize Page tables to 0 */
        leal    pgtable(%ebx), %edi
        xorl    %eax, %eax
        movl    $((4096*6)/4), %ecx
@@ -155,7 +154,8 @@ ENTRY(startup_32)
        btsl    $_EFER_LME, %eax
        wrmsr
 
-       /* Setup for the jump to 64bit mode
+       /*
+        * Setup for the jump to 64bit mode
         *
         * When the jump is performend we will be in long mode but
         * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1
@@ -184,7 +184,8 @@ no_longmode:
 
 #include "../../kernel/verify_cpu_64.S"
 
-       /* Be careful here startup_64 needs to be at a predictable
+       /*
+        * Be careful here startup_64 needs to be at a predictable
         * address so I can export it in an ELF header.  Bootloaders
         * should look at the ELF header to find this address, as
         * it may change in the future.
@@ -192,7 +193,8 @@ no_longmode:
        .code64
        .org 0x200
 ENTRY(startup_64)
-       /* We come here either from startup_32 or directly from a
+       /*
+        * We come here either from startup_32 or directly from a
         * 64bit bootloader.  If we come here from a bootloader we depend on
         * an identity mapped page table being provied that maps our
         * entire text+data+bss and hopefully all of memory.
@@ -209,50 +211,54 @@ ENTRY(startup_64)
        movl    $0x20, %eax
        ltr     %ax
 
-       /* Compute the decompressed kernel start address.  It is where
+       /*
+        * Compute the decompressed kernel start address.  It is where
         * we were loaded at aligned to a 2M boundary. %rbp contains the
         * decompressed kernel start address.
         *
         * If it is a relocatable kernel then decompress and run the kernel
         * from load address aligned to 2MB addr, otherwise decompress and
-        * run the kernel from CONFIG_PHYSICAL_START
+        * run the kernel from LOAD_PHYSICAL_ADDR
+        *
+        * We cannot rely on the calculation done in 32-bit mode, since we
+        * may have been invoked via the 64-bit entry point.
         */
 
        /* Start with the delta to where the kernel will run at. */
 #ifdef CONFIG_RELOCATABLE
        leaq    startup_32(%rip) /* - $startup_32 */, %rbp
-       addq    $(PMD_PAGE_SIZE - 1), %rbp
-       andq    $PMD_PAGE_MASK, %rbp
-       movq    %rbp, %rbx
+       movl    BP_kernel_alignment(%rsi), %eax
+       decl    %eax
+       addq    %rax, %rbp
+       notq    %rax
+       andq    %rax, %rbp
 #else
-       movq    $CONFIG_PHYSICAL_START, %rbp
-       movq    %rbp, %rbx
+       movq    $LOAD_PHYSICAL_ADDR, %rbp
 #endif
 
-       /* Replace the compressed data size with the uncompressed size */
-       movl    input_len(%rip), %eax
-       subq    %rax, %rbx
-       movl    output_len(%rip), %eax
-       addq    %rax, %rbx
-       /* Add 8 bytes for every 32K input block */
-       shrq    $12, %rax
-       addq    %rax, %rbx
-       /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */
-       addq    $(32768 + 18 + 4095), %rbx
-       andq    $~4095, %rbx
-
-/* Copy the compressed kernel to the end of our buffer
+       /* Target address to relocate to for decompression */
+       leaq    z_extract_offset(%rbp), %rbx
+
+       /* Set up the stack */
+       leaq    boot_stack_end(%rbx), %rsp
+
+       /* Zero EFLAGS */
+       pushq   $0
+       popfq
+
+/*
+ * Copy the compressed kernel to the end of our buffer
  * where decompression in place becomes safe.
  */
-       leaq    _end_before_pgt(%rip), %r8
-       leaq    _end_before_pgt(%rbx), %r9
-       movq    $_end_before_pgt /* - $startup_32 */, %rcx
-1:     subq    $8, %r8
-       subq    $8, %r9
-       movq    0(%r8), %rax
-       movq    %rax, 0(%r9)
-       subq    $8, %rcx
-       jnz     1b
+       pushq   %rsi
+       leaq    (_bss-8)(%rip), %rsi
+       leaq    (_bss-8)(%rbx), %rdi
+       movq    $_bss /* - $startup_32 */, %rcx
+       shrq    $3, %rcx
+       std
+       rep     movsq
+       cld
+       popq    %rsi
 
 /*
  * Jump to the relocated address.
@@ -260,37 +266,28 @@ ENTRY(startup_64)
        leaq    relocated(%rbx), %rax
        jmp     *%rax
 
-.section ".text"
+       .text
 relocated:
 
 /*
- * Clear BSS
+ * Clear BSS (stack is currently empty)
  */
-       xorq    %rax, %rax
-       leaq    _edata(%rbx), %rdi
-       leaq    _end_before_pgt(%rbx), %rcx
+       xorl    %eax, %eax
+       leaq    _bss(%rip), %rdi
+       leaq    _ebss(%rip), %rcx
        subq    %rdi, %rcx
-       cld
-       rep
-       stosb
-
-       /* Setup the stack */
-       leaq    boot_stack_end(%rip), %rsp
-
-       /* zero EFLAGS after setting rsp */
-       pushq   $0
-       popfq
+       shrq    $3, %rcx
+       rep     stosq
 
 /*
  * Do the decompression, and jump to the new kernel..
  */
-       pushq   %rsi                    # Save the real mode argument
-       movq    %rsi, %rdi              # real mode address
-       leaq    boot_heap(%rip), %rsi   # malloc area for uncompression
-       leaq    input_data(%rip), %rdx  # input_data
-       movl    input_len(%rip), %eax
-       movq    %rax, %rcx              # input_len
-       movq    %rbp, %r8               # output
+       pushq   %rsi                    /* Save the real mode argument */
+       movq    %rsi, %rdi              /* real mode address */
+       leaq    boot_heap(%rip), %rsi   /* malloc area for uncompression */
+       leaq    input_data(%rip), %rdx  /* input_data */
+       movl    $z_input_len, %ecx      /* input_len */
+       movq    %rbp, %r8               /* output target address */
        call    decompress_kernel
        popq    %rsi
 
@@ -311,11 +308,21 @@ gdt:
        .quad   0x0000000000000000      /* TS continued */
 gdt_end:
 
-.bss
-/* Stack and heap for uncompression */
-.balign 4
+/*
+ * Stack and heap for uncompression
+ */
+       .bss
+       .balign 4
 boot_heap:
        .fill BOOT_HEAP_SIZE, 1, 0
 boot_stack:
        .fill BOOT_STACK_SIZE, 1, 0
 boot_stack_end:
+
+/*
+ * Space for page tables (not in .bss so not zeroed)
+ */
+       .section ".pgtable","a",@nobits
+       .balign 4096
+pgtable:
+       .fill 6*4096, 1, 0
index e45be73684ffe3bd5559029eb86cf66ec00ff250..842b2a36174a2a2b6347851d7f1069878fb5cb4b 100644 (file)
@@ -325,20 +325,18 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
        free_mem_ptr     = heap;        /* Heap */
        free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
 
+       if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
+               error("Destination address inappropriately aligned");
 #ifdef CONFIG_X86_64
-       if ((unsigned long)output & (__KERNEL_ALIGN - 1))
-               error("Destination address not 2M aligned");
-       if ((unsigned long)output >= 0xffffffffffUL)
+       if (heap > 0x3fffffffffffUL)
                error("Destination address too large");
 #else
-       if ((u32)output & (CONFIG_PHYSICAL_ALIGN - 1))
-               error("Destination address not CONFIG_PHYSICAL_ALIGN aligned");
        if (heap > ((-__PAGE_OFFSET-(512<<20)-1) & 0x7fffffff))
                error("Destination address too large");
+#endif
 #ifndef CONFIG_RELOCATABLE
-       if ((u32)output != LOAD_PHYSICAL_ADDR)
+       if ((unsigned long)output != LOAD_PHYSICAL_ADDR)
                error("Wrong destination address");
-#endif
 #endif
 
        if (!quiet)
diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c
new file mode 100644 (file)
index 0000000..bcbd36c
--- /dev/null
@@ -0,0 +1,97 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *  Copyright (C) 2009 Intel Corporation. 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 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ *
+ *  H. Peter Anvin <hpa@linux.intel.com>
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Compute the desired load offset from a compressed program; outputs
+ * a small assembly wrapper with the appropriate symbols defined.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+static uint32_t getle32(const void *p)
+{
+       const uint8_t *cp = p;
+
+       return (uint32_t)cp[0] + ((uint32_t)cp[1] << 8) +
+               ((uint32_t)cp[2] << 16) + ((uint32_t)cp[3] << 24);
+}
+
+int main(int argc, char *argv[])
+{
+       uint32_t olen;
+       long ilen;
+       unsigned long offs;
+       FILE *f;
+
+       if (argc < 2) {
+               fprintf(stderr, "Usage: %s compressed_file\n", argv[0]);
+               return 1;
+       }
+
+       /* Get the information for the compressed kernel image first */
+
+       f = fopen(argv[1], "r");
+       if (!f) {
+               perror(argv[1]);
+               return 1;
+       }
+
+
+       if (fseek(f, -4L, SEEK_END)) {
+               perror(argv[1]);
+       }
+       fread(&olen, sizeof olen, 1, f);
+       ilen = ftell(f);
+       olen = getle32(&olen);
+       fclose(f);
+
+       /*
+        * Now we have the input (compressed) and output (uncompressed)
+        * sizes, compute the necessary decompression offset...
+        */
+
+       offs = (olen > ilen) ? olen - ilen : 0;
+       offs += olen >> 12;     /* Add 8 bytes for each 32K block */
+       offs += 32*1024 + 18;   /* Add 32K + 18 bytes slack */
+       offs = (offs+4095) & ~4095; /* Round to a 4K boundary */
+
+       printf(".section \".rodata.compressed\",\"a\",@progbits\n");
+       printf(".globl z_input_len\n");
+       printf("z_input_len = %lu\n", ilen);
+       printf(".globl z_output_len\n");
+       printf("z_output_len = %lu\n", (unsigned long)olen);
+       printf(".globl z_extract_offset\n");
+       printf("z_extract_offset = 0x%lx\n", offs);
+       /* z_extract_offset_negative allows simplification of head_32.S */
+       printf(".globl z_extract_offset_negative\n");
+       printf("z_extract_offset_negative = -0x%lx\n", offs);
+
+       printf(".globl input_data, input_data_end\n");
+       printf("input_data:\n");
+       printf(".incbin \"%s\"\n", argv[1]);
+       printf("input_data_end:\n");
+
+       return 0;
+}
similarity index 57%
rename from arch/x86/boot/compressed/vmlinux_64.lds
rename to arch/x86/boot/compressed/vmlinux.lds.S
index bef1ac891bce9987d2693cdc1ff601457af0d6c4..cc353e1b3ffd49185f2cf0683e21894462f0c1de 100644 (file)
@@ -1,6 +1,17 @@
-OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_FORMAT(CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT)
+
+#undef i386
+
+#include <asm/page_types.h>
+
+#ifdef CONFIG_X86_64
 OUTPUT_ARCH(i386:x86-64)
 ENTRY(startup_64)
+#else
+OUTPUT_ARCH(i386)
+ENTRY(startup_32)
+#endif
+
 SECTIONS
 {
        /* Be careful parts of head_64.S assume startup_32 is at
@@ -33,16 +44,22 @@ SECTIONS
                *(.data.*)
                _edata = . ;
        }
+       . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
        .bss : {
                _bss = . ;
                *(.bss)
                *(.bss.*)
                *(COMMON)
-               . = ALIGN(8);
-               _end_before_pgt = . ;
-               . = ALIGN(4096);
-               pgtable = . ;
-               . = . + 4096 * 6;
+               . = ALIGN(8);   /* For convenience during zeroing */
                _ebss = .;
        }
+#ifdef CONFIG_X86_64
+       . = ALIGN(PAGE_SIZE);
+       .pgtable : {
+               _pgtable = . ;
+               *(.pgtable)
+               _epgtable = . ;
+       }
+#endif
+       _end = .;
 }
diff --git a/arch/x86/boot/compressed/vmlinux.scr b/arch/x86/boot/compressed/vmlinux.scr
deleted file mode 100644 (file)
index f02382a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-SECTIONS
-{
-  .rodata.compressed : {
-       input_len = .;
-       LONG(input_data_end - input_data) input_data = .;
-       *(.data)
-       output_len = . - 4;
-       input_data_end = .;
-       }
-}
diff --git a/arch/x86/boot/compressed/vmlinux_32.lds b/arch/x86/boot/compressed/vmlinux_32.lds
deleted file mode 100644 (file)
index bb3c483..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
-OUTPUT_ARCH(i386)
-ENTRY(startup_32)
-SECTIONS
-{
-       /* Be careful parts of head_32.S assume startup_32 is at
-        * address 0.
-        */
-       . = 0;
-       .text.head : {
-               _head = . ;
-               *(.text.head)
-               _ehead = . ;
-       }
-       .rodata.compressed : {
-               *(.rodata.compressed)
-       }
-       .text : {
-               _text = .;      /* Text */
-               *(.text)
-               *(.text.*)
-               _etext = . ;
-       }
-       .rodata : {
-               _rodata = . ;
-               *(.rodata)       /* read-only data */
-               *(.rodata.*)
-               _erodata = . ;
-       }
-       .data : {
-               _data = . ;
-               *(.data)
-               *(.data.*)
-               _edata = . ;
-       }
-       .bss : {
-               _bss = . ;
-               *(.bss)
-               *(.bss.*)
-               *(COMMON)
-               _end = . ;
-       }
-}
index 1aae8f3e5ca1912b6eb60ad75e3c120af1110bed..c501a5b466f8495c26d3eff4de1cddb97613fca4 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.
  */
 static int read_mbr(u8 devno, void *buf)
 {
-       u16 ax, bx, cx, dx;
+       struct biosregs ireg, oreg;
 
-       ax = 0x0201;            /* Legacy Read, one sector */
-       cx = 0x0001;            /* Sector 0-0-1 */
-       dx = devno;
-       bx = (size_t)buf;
-       asm volatile("pushfl; stc; int $0x13; setc %%al; popfl"
-                    : "+a" (ax), "+c" (cx), "+d" (dx), "+b" (bx)
-                    : : "esi", "edi", "memory");
+       initregs(&ireg);
+       ireg.ax = 0x0201;               /* Legacy Read, one sector */
+       ireg.cx = 0x0001;               /* Sector 0-0-1 */
+       ireg.dl = devno;
+       ireg.bx = (size_t)buf;
 
-       return -(u8)ax;         /* 0 or -1 */
+       intcall(0x13, &ireg, &oreg);
+
+       return -(oreg.eflags & X86_EFLAGS_CF); /* 0 or -1 */
 }
 
 static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig)
@@ -72,56 +73,46 @@ static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig)
 
 static int get_edd_info(u8 devno, struct edd_info *ei)
 {
-       u16 ax, bx, cx, dx, di;
+       struct biosregs ireg, oreg;
 
        memset(ei, 0, sizeof *ei);
 
        /* Check Extensions Present */
 
-       ax = 0x4100;
-       bx = EDDMAGIC1;
-       dx = devno;
-       asm("pushfl; stc; int $0x13; setc %%al; popfl"
-           : "+a" (ax), "+b" (bx), "=c" (cx), "+d" (dx)
-           : : "esi", "edi");
+       initregs(&ireg);
+       ireg.ah = 0x41;
+       ireg.bx = EDDMAGIC1;
+       ireg.dl = devno;
+       intcall(0x13, &ireg, &oreg);
 
-       if ((u8)ax)
+       if (oreg.eflags & X86_EFLAGS_CF)
                return -1;      /* No extended information */
 
-       if (bx != EDDMAGIC2)
+       if (oreg.bx != EDDMAGIC2)
                return -1;
 
        ei->device  = devno;
-       ei->version = ax >> 8;  /* EDD version number */
-       ei->interface_support = cx; /* EDD functionality subsets */
+       ei->version = oreg.ah;           /* EDD version number */
+       ei->interface_support = oreg.cx; /* EDD functionality subsets */
 
        /* Extended Get Device Parameters */
 
        ei->params.length = sizeof(ei->params);
-       ax = 0x4800;
-       dx = devno;
-       asm("pushfl; int $0x13; popfl"
-           : "+a" (ax), "+d" (dx), "=m" (ei->params)
-           : "S" (&ei->params)
-           : "ebx", "ecx", "edi");
+       ireg.ah = 0x48;
+       ireg.si = (size_t)&ei->params;
+       intcall(0x13, &ireg, &oreg);
 
        /* Get legacy CHS parameters */
 
        /* Ralf Brown recommends setting ES:DI to 0:0 */
-       ax = 0x0800;
-       dx = devno;
-       di = 0;
-       asm("pushw %%es; "
-           "movw %%di,%%es; "
-           "pushfl; stc; int $0x13; setc %%al; popfl; "
-           "popw %%es"
-           : "+a" (ax), "=b" (bx), "=c" (cx), "+d" (dx), "+D" (di)
-           : : "esi");
-
-       if ((u8)ax == 0) {
-               ei->legacy_max_cylinder = (cx >> 8) + ((cx & 0xc0) << 2);
-               ei->legacy_max_head = dx >> 8;
-               ei->legacy_sectors_per_track = cx & 0x3f;
+       ireg.ah = 0x08;
+       ireg.es = 0;
+       intcall(0x13, &ireg, &oreg);
+
+       if (!(oreg.eflags & X86_EFLAGS_CF)) {
+               ei->legacy_max_cylinder = oreg.ch + ((oreg.cl & 0xc0) << 2);
+               ei->legacy_max_head = oreg.dh;
+               ei->legacy_sectors_per_track = oreg.cl & 0x3f;
        }
 
        return 0;
index 5d84d1c74e4c6d2a84666c7b7125641b00a1dcad..b31cc54b46410f89b4120702b1d1b018a79e204d 100644 (file)
@@ -22,7 +22,8 @@
 #include <asm/page_types.h>
 #include <asm/setup.h>
 #include "boot.h"
-#include "offsets.h"
+#include "voffset.h"
+#include "zoffset.h"
 
 BOOTSEG                = 0x07C0                /* original address of boot-sector */
 SYSSEG         = 0x1000                /* historical load address >> 4 */
@@ -115,7 +116,7 @@ _start:
        # Part 2 of the header, from the old setup.S
 
                .ascii  "HdrS"          # header signature
-               .word   0x0209          # header version number (>= 0x0105)
+               .word   0x020a          # header version number (>= 0x0105)
                                        # or else old loadlin-1.5 will fail)
                .globl realmode_swtch
 realmode_swtch:        .word   0, 0            # default_switch, SETUPSEG
@@ -168,7 +169,11 @@ heap_end_ptr:      .word   _end+STACK_SIZE-512
                                        # end of setup code can be used by setup
                                        # for local heap purposes.
 
-pad1:          .word   0
+ext_loader_ver:
+               .byte   0               # Extended boot loader version
+ext_loader_type:
+               .byte   0               # Extended boot loader type
+
 cmd_line_ptr:  .long   0               # (Header version 0x0202 or later)
                                        # If nonzero, a 32-bit pointer
                                        # to the kernel command line.
@@ -200,7 +205,7 @@ relocatable_kernel:    .byte 1
 #else
 relocatable_kernel:    .byte 0
 #endif
-pad2:                  .byte 0
+min_alignment:         .byte MIN_KERNEL_ALIGN_LG2      # minimum alignment
 pad3:                  .word 0
 
 cmdline_size:   .long   COMMAND_LINE_SIZE-1     #length of the command line,
@@ -212,16 +217,27 @@ hardware_subarch: .long 0                 # subarchitecture, added with 2.07
 
 hardware_subarch_data: .quad 0
 
-payload_offset:                .long input_data
-payload_length:                .long input_data_end-input_data
+payload_offset:                .long ZO_input_data
+payload_length:                .long ZO_z_input_len
 
 setup_data:            .quad 0                 # 64-bit physical pointer to
                                                # single linked list of
                                                # struct setup_data
 
+pref_address:          .quad LOAD_PHYSICAL_ADDR        # preferred load addr
+
+#define ZO_INIT_SIZE   (ZO__end - ZO_startup_32 + ZO_z_extract_offset)
+#define VO_INIT_SIZE   (VO__end - VO__text)
+#if ZO_INIT_SIZE > VO_INIT_SIZE
+#define INIT_SIZE ZO_INIT_SIZE
+#else
+#define INIT_SIZE VO_INIT_SIZE
+#endif
+init_size:             .long INIT_SIZE         # kernel initialization size
+
 # End of setup header #####################################################
 
-       .section ".inittext", "ax"
+       .section ".entrytext", "ax"
 start_of_setup:
 #ifdef SAFE_RESET_DISK_CONTROLLER
 # Reset the disk controller.
index 58f0415d3ae09261d55c11d12855e3bc75fc4bdf..140172b895bd32c32ca2819ef776718f77df3103 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.
@@ -61,11 +62,10 @@ static void copy_boot_params(void)
  */
 static void keyboard_set_repeat(void)
 {
-       u16 ax = 0x0305;
-       u16 bx = 0;
-       asm volatile("int $0x16"
-                    : "+a" (ax), "+b" (bx)
-                    : : "ecx", "edx", "esi", "edi");
+       struct biosregs ireg;
+       initregs(&ireg);
+       ireg.ax = 0x0305;
+       intcall(0x16, &ireg, NULL);
 }
 
 /*
@@ -73,18 +73,22 @@ static void keyboard_set_repeat(void)
  */
 static void query_ist(void)
 {
+       struct biosregs ireg, oreg;
+
        /* Some older BIOSes apparently crash on this call, so filter
           it from machines too old to have SpeedStep at all. */
        if (cpu.level < 6)
                return;
 
-       asm("int $0x15"
-           : "=a" (boot_params.ist_info.signature),
-             "=b" (boot_params.ist_info.command),
-             "=c" (boot_params.ist_info.event),
-             "=d" (boot_params.ist_info.perf_level)
-           : "a" (0x0000e980),  /* IST Support */
-             "d" (0x47534943)); /* Request value */
+       initregs(&ireg);
+       ireg.ax  = 0xe980;       /* IST Support */
+       ireg.edx = 0x47534943;   /* Request value */
+       intcall(0x15, &ireg, &oreg);
+
+       boot_params.ist_info.signature  = oreg.eax;
+       boot_params.ist_info.command    = oreg.ebx;
+       boot_params.ist_info.event      = oreg.ecx;
+       boot_params.ist_info.perf_level = oreg.edx;
 }
 
 /*
@@ -93,13 +97,12 @@ static void query_ist(void)
 static void set_bios_mode(void)
 {
 #ifdef CONFIG_X86_64
-       u32 eax, ebx;
+       struct biosregs ireg;
 
-       eax = 0xec00;
-       ebx = 2;
-       asm volatile("int $0x15"
-                    : "+a" (eax), "+b" (ebx)
-                    : : "ecx", "edx", "esi", "edi");
+       initregs(&ireg);
+       ireg.ax = 0xec00;
+       ireg.bx = 2;
+       intcall(0x15, &ireg, NULL);
 #endif
 }
 
index 911eaae5d696427c98fdad7f344a14bdc0340efc..a95a531148ef9562ca408a9f451914748159b71e 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.
 
 int query_mca(void)
 {
-       u8 err;
-       u16 es, bx, len;
-
-       asm("pushw %%es ; "
-           "int $0x15 ; "
-           "setc %0 ; "
-           "movw %%es, %1 ; "
-           "popw %%es"
-           : "=acd" (err), "=acdSD" (es), "=b" (bx)
-           : "a" (0xc000));
-
-       if (err)
+       struct biosregs ireg, oreg;
+       u16 len;
+
+       initregs(&ireg);
+       ireg.ah = 0xc0;
+       intcall(0x15, &ireg, &oreg);
+
+       if (oreg.eflags & X86_EFLAGS_CF)
                return -1;      /* No MCA present */
 
-       set_fs(es);
-       len = rdfs16(bx);
+       set_fs(oreg.es);
+       len = rdfs16(oreg.bx);
 
        if (len > sizeof(boot_params.sys_desc_table))
                len = sizeof(boot_params.sys_desc_table);
 
-       copy_from_fs(&boot_params.sys_desc_table, bx, len);
+       copy_from_fs(&boot_params.sys_desc_table, oreg.bx, len);
        return 0;
 }
index 74b3d2ba84e90a39bb29f166278ce47bcf56437c..cae3feb1035e3da73826b518de4d47c15ad4e58d 100644 (file)
 static int detect_memory_e820(void)
 {
        int count = 0;
-       u32 next = 0;
-       u32 size, id, edi;
-       u8 err;
+       struct biosregs ireg, oreg;
        struct e820entry *desc = boot_params.e820_map;
        static struct e820entry buf; /* static so it is zeroed */
 
+       initregs(&ireg);
+       ireg.ax  = 0xe820;
+       ireg.cx  = sizeof buf;
+       ireg.edx = SMAP;
+       ireg.di  = (size_t)&buf;
+
        /*
         * Note: at least one BIOS is known which assumes that the
         * buffer pointed to by one e820 call is the same one as
@@ -41,22 +45,13 @@ static int detect_memory_e820(void)
         */
 
        do {
-               size = sizeof buf;
-
-               /* 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),
-                     "=D" (edi), "+m" (buf)
-                   : "D" (&buf), "d" (SMAP), "a" (0xe820)
-                   : "esi");
+               intcall(0x15, &ireg, &oreg);
+               ireg.ebx = oreg.ebx; /* for next iteration... */
 
                /* BIOSes which terminate the chain with CF = 1 as opposed
                   to %ebx = 0 don't always report the SMAP signature on
                   the final, failing, probe. */
-               if (err)
+               if (oreg.eflags & X86_EFLAGS_CF)
                        break;
 
                /* Some BIOSes stop returning SMAP in the middle of
@@ -64,60 +59,64 @@ static int detect_memory_e820(void)
                   screwed up the map at that point, we might have a
                   partial map, the full map, or complete garbage, so
                   just return failure. */
-               if (id != SMAP) {
+               if (oreg.eax != SMAP) {
                        count = 0;
                        break;
                }
 
                *desc++ = buf;
                count++;
-       } while (next && count < ARRAY_SIZE(boot_params.e820_map));
+       } while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_map));
 
        return boot_params.e820_entries = count;
 }
 
 static int detect_memory_e801(void)
 {
-       u16 ax, bx, cx, dx;
-       u8 err;
+       struct biosregs ireg, oreg;
 
-       bx = cx = dx = 0;
-       ax = 0xe801;
-       asm("stc; int $0x15; setc %0"
-           : "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx));
+       initregs(&ireg);
+       ireg.ax = 0xe801;
+       intcall(0x15, &ireg, &oreg);
 
-       if (err)
+       if (oreg.eflags & X86_EFLAGS_CF)
                return -1;
 
        /* Do we really need to do this? */
-       if (cx || dx) {
-               ax = cx;
-               bx = dx;
+       if (oreg.cx || oreg.dx) {
+               oreg.ax = oreg.cx;
+               oreg.bx = oreg.dx;
        }
 
-       if (ax > 15*1024)
+       if (oreg.ax > 15*1024) {
                return -1;      /* Bogus! */
-
-       /* This ignores memory above 16MB if we have a memory hole
-          there.  If someone actually finds a machine with a memory
-          hole at 16MB and no support for 0E820h they should probably
-          generate a fake e820 map. */
-       boot_params.alt_mem_k = (ax == 15*1024) ? (dx << 6)+ax : ax;
+       } else if (oreg.ax == 15*1024) {
+               boot_params.alt_mem_k = (oreg.dx << 6) + oreg.ax;
+       } else {
+               /*
+                * This ignores memory above 16MB if we have a memory
+                * hole there.  If someone actually finds a machine
+                * with a memory hole at 16MB and no support for
+                * 0E820h they should probably generate a fake e820
+                * map.
+                */
+               boot_params.alt_mem_k = oreg.ax;
+       }
 
        return 0;
 }
 
 static int detect_memory_88(void)
 {
-       u16 ax;
-       u8 err;
+       struct biosregs ireg, oreg;
 
-       ax = 0x8800;
-       asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax));
+       initregs(&ireg);
+       ireg.ah = 0x88;
+       intcall(0x15, &ireg, &oreg);
 
-       boot_params.screen_info.ext_mem_k = ax;
+       boot_params.screen_info.ext_mem_k = oreg.ax;
 
-       return -err;
+       return -(oreg.eflags & X86_EFLAGS_CF); /* 0 or -1 */
 }
 
 int detect_memory(void)
diff --git a/arch/x86/boot/regs.c b/arch/x86/boot/regs.c
new file mode 100644 (file)
index 0000000..958019b
--- /dev/null
@@ -0,0 +1,29 @@
+/* -----------------------------------------------------------------------
+ *
+ *   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 or (at your
+ *   option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Simple helper function for initializing a register set.
+ *
+ * Note that this sets EFLAGS_CF in the input register set; this
+ * makes it easier to catch functions which do nothing but don't
+ * explicitly set CF.
+ */
+
+#include "boot.h"
+
+void initregs(struct biosregs *reg)
+{
+       memset(reg, 0, sizeof *reg);
+       reg->eflags |= X86_EFLAGS_CF;
+       reg->ds = ds();
+       reg->es = ds();
+       reg->fs = fs();
+       reg->gs = gs();
+}
index bb8dc2de796936c6a21d0b1bfbd934ca8a3e5877..0f6ec455a2b13a58151861b2e8d307776d866742 100644 (file)
@@ -15,8 +15,11 @@ SECTIONS
 
        . = 497;
        .header         : { *(.header) }
+       .entrytext      : { *(.entrytext) }
        .inittext       : { *(.inittext) }
        .initdata       : { *(.initdata) }
+       __end_init = .;
+
        .text           : { *(.text) }
        .text32         : { *(.text32) }
 
@@ -52,4 +55,7 @@ SECTIONS
 
        . = ASSERT(_end <= 0x8000, "Setup too big!");
        . = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!");
+       /* Necessary for the very-old-loader check to work... */
+       . = ASSERT(__end_init <= 5*512, "init sections too big!");
+
 }
index 7e8e8b25f5f6c89defd0df4064a61e3e16a4ea06..01ec69c901c7a595e88748f24880a5104af553fe 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.
 
 void __attribute__((section(".inittext"))) putchar(int ch)
 {
-       unsigned char c = ch;
+       struct biosregs ireg;
 
-       if (c == '\n')
+       if (ch == '\n')
                putchar('\r');  /* \n -> \r\n */
 
-       /* int $0x10 is known to have bugs involving touching registers
-          it shouldn't.  Be extra conservative... */
-       asm volatile("pushal; pushw %%ds; int $0x10; popw %%ds; popal"
-                    : : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch));
+       initregs(&ireg);
+       ireg.bx = 0x0007;
+       ireg.cx = 0x0001;
+       ireg.ah = 0x0e;
+       ireg.al = ch;
+       intcall(0x10, &ireg, NULL);
 }
 
 void __attribute__((section(".inittext"))) puts(const char *str)
 {
-       int n = 0;
-       while (*str) {
+       while (*str)
                putchar(*str++);
-               n++;
-       }
 }
 
 /*
@@ -49,14 +49,13 @@ void __attribute__((section(".inittext"))) puts(const char *str)
 
 static u8 gettime(void)
 {
-       u16 ax = 0x0200;
-       u16 cx, dx;
+       struct biosregs ireg, oreg;
 
-       asm volatile("int $0x1a"
-                    : "+a" (ax), "=c" (cx), "=d" (dx)
-                    : : "ebx", "esi", "edi");
+       initregs(&ireg);
+       ireg.ah = 0x02;
+       intcall(0x1a, &ireg, &oreg);
 
-       return dx >> 8;
+       return oreg.dh;
 }
 
 /*
@@ -64,19 +63,24 @@ static u8 gettime(void)
  */
 int getchar(void)
 {
-       u16 ax = 0;
-       asm volatile("int $0x16" : "+a" (ax));
+       struct biosregs ireg, oreg;
+
+       initregs(&ireg);
+       /* ireg.ah = 0x00; */
+       intcall(0x16, &ireg, &oreg);
 
-       return ax & 0xff;
+       return oreg.al;
 }
 
 static int kbd_pending(void)
 {
-       u8 pending;
-       asm volatile("int $0x16; setnz %0"
-                    : "=qm" (pending)
-                    : "a" (0x0100));
-       return pending;
+       struct biosregs ireg, oreg;
+
+       initregs(&ireg);
+       ireg.ah = 0x01;
+       intcall(0x16, &ireg, &oreg);
+
+       return !(oreg.eflags & X86_EFLAGS_ZF);
 }
 
 void kbd_flush(void)
index 3fa979c9c363a5dbe6f9ce6d754636ed301d01b1..d660be4923634ebfc0160b468a569289c02bce90 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.
@@ -29,21 +30,21 @@ static int bios_set_mode(struct mode_info *mi)
 
 static int set_bios_mode(u8 mode)
 {
-       u16 ax;
+       struct biosregs ireg, oreg;
        u8 new_mode;
 
-       ax = mode;              /* AH=0x00 Set Video Mode */
-       asm volatile(INT10
-                    : "+a" (ax)
-                    : : "ebx", "ecx", "edx", "esi", "edi");
+       initregs(&ireg);
+       ireg.al = mode;         /* AH=0x00 Set Video Mode */
+       intcall(0x10, &ireg, NULL);
 
-       ax = 0x0f00;            /* Get Current Video Mode */
-       asm volatile(INT10
-                    : "+a" (ax)
-                    : : "ebx", "ecx", "edx", "esi", "edi");
+
+       ireg.ah = 0x0f;         /* Get Current Video Mode */
+       intcall(0x10, &ireg, &oreg);
 
        do_restore = 1;         /* Assume video contents were lost */
-       new_mode = ax & 0x7f;   /* Not all BIOSes are clean with the top bit */
+
+       /* Not all BIOSes are clean with the top bit */
+       new_mode = ireg.al & 0x7f;
 
        if (new_mode == mode)
                return 0;       /* Mode change OK */
@@ -53,10 +54,8 @@ static int set_bios_mode(u8 mode)
                /* Mode setting failed, but we didn't end up where we
                   started.  That's bad.  Try to revert to the original
                   video mode. */
-               ax = boot_params.screen_info.orig_video_mode;
-               asm volatile(INT10
-                            : "+a" (ax)
-                            : : "ebx", "ecx", "edx", "esi", "edi");
+               ireg.ax = boot_params.screen_info.orig_video_mode;
+               intcall(0x10, &ireg, NULL);
        }
 #endif
        return -1;
index 4a58c8ce3f6960534931409905103aa7465aa9d6..c700147d6ffb24b72fbbf43ff954d4cfd268f137 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.
@@ -31,7 +32,7 @@ static inline void vesa_store_mode_params_graphics(void) {}
 static int vesa_probe(void)
 {
 #if defined(CONFIG_VIDEO_VESA) || defined(CONFIG_FIRMWARE_EDID)
-       u16 ax, cx, di;
+       struct biosregs ireg, oreg;
        u16 mode;
        addr_t mode_ptr;
        struct mode_info *mi;
@@ -39,13 +40,12 @@ static int vesa_probe(void)
 
        video_vesa.modes = GET_HEAP(struct mode_info, 0);
 
-       ax = 0x4f00;
-       di = (size_t)&vginfo;
-       asm(INT10
-           : "+a" (ax), "+D" (di), "=m" (vginfo)
-           : : "ebx", "ecx", "edx", "esi");
+       initregs(&ireg);
+       ireg.ax = 0x4f00;
+       ireg.di = (size_t)&vginfo;
+       intcall(0x10, &ireg, &oreg);
 
-       if (ax != 0x004f ||
+       if (ireg.ax != 0x004f ||
            vginfo.signature != VESA_MAGIC ||
            vginfo.version < 0x0102)
                return 0;       /* Not present */
@@ -65,14 +65,12 @@ static int vesa_probe(void)
 
                memset(&vminfo, 0, sizeof vminfo); /* Just in case... */
 
-               ax = 0x4f01;
-               cx = mode;
-               di = (size_t)&vminfo;
-               asm(INT10
-                   : "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo)
-                   : : "ebx", "edx", "esi");
+               ireg.ax = 0x4f01;
+               ireg.cx = mode;
+               ireg.di = (size_t)&vminfo;
+               intcall(0x10, &ireg, &oreg);
 
-               if (ax != 0x004f)
+               if (ireg.ax != 0x004f)
                        continue;
 
                if ((vminfo.mode_attr & 0x15) == 0x05) {
@@ -111,20 +109,19 @@ static int vesa_probe(void)
 
 static int vesa_set_mode(struct mode_info *mode)
 {
-       u16 ax, bx, cx, di;
+       struct biosregs ireg, oreg;
        int is_graphic;
        u16 vesa_mode = mode->mode - VIDEO_FIRST_VESA;
 
        memset(&vminfo, 0, sizeof vminfo); /* Just in case... */
 
-       ax = 0x4f01;
-       cx = vesa_mode;
-       di = (size_t)&vminfo;
-       asm(INT10
-           : "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo)
-           : : "ebx", "edx", "esi");
+       initregs(&ireg);
+       ireg.ax = 0x4f01;
+       ireg.cx = vesa_mode;
+       ireg.di = (size_t)&vminfo;
+       intcall(0x10, &ireg, &oreg);
 
-       if (ax != 0x004f)
+       if (oreg.ax != 0x004f)
                return -1;
 
        if ((vminfo.mode_attr & 0x15) == 0x05) {
@@ -141,14 +138,12 @@ static int vesa_set_mode(struct mode_info *mode)
        }
 
 
-       ax = 0x4f02;
-       bx = vesa_mode;
-       di = 0;
-       asm volatile(INT10
-                    : "+a" (ax), "+b" (bx), "+D" (di)
-                    : : "ecx", "edx", "esi");
+       initregs(&ireg);
+       ireg.ax = 0x4f02;
+       ireg.bx = vesa_mode;
+       intcall(0x10, &ireg, &oreg);
 
-       if (ax != 0x004f)
+       if (oreg.ax != 0x004f)
                return -1;
 
        graphic_mode = is_graphic;
@@ -171,50 +166,45 @@ static int vesa_set_mode(struct mode_info *mode)
 /* Switch DAC to 8-bit mode */
 static void vesa_dac_set_8bits(void)
 {
+       struct biosregs ireg, oreg;
        u8 dac_size = 6;
 
        /* If possible, switch the DAC to 8-bit mode */
        if (vginfo.capabilities & 1) {
-               u16 ax, bx;
-
-               ax = 0x4f08;
-               bx = 0x0800;
-               asm volatile(INT10
-                            : "+a" (ax), "+b" (bx)
-                            : : "ecx", "edx", "esi", "edi");
-
-               if (ax == 0x004f)
-                       dac_size = bx >> 8;
+               initregs(&ireg);
+               ireg.ax = 0x4f08;
+               ireg.bh = 0x08;
+               intcall(0x10, &ireg, &oreg);
+               if (oreg.ax == 0x004f)
+                       dac_size = oreg.bh;
        }
 
        /* Set the color sizes to the DAC size, and offsets to 0 */
-       boot_params.screen_info.red_size = dac_size;
+       boot_params.screen_info.red_size   = dac_size;
        boot_params.screen_info.green_size = dac_size;
-       boot_params.screen_info.blue_size = dac_size;
-       boot_params.screen_info.rsvd_size = dac_size;
+       boot_params.screen_info.blue_size  = dac_size;
+       boot_params.screen_info.rsvd_size  = dac_size;
 
-       boot_params.screen_info.red_pos = 0;
-       boot_params.screen_info.green_pos = 0;
-       boot_params.screen_info.blue_pos = 0;
-       boot_params.screen_info.rsvd_pos = 0;
+       boot_params.screen_info.red_pos    = 0;
+       boot_params.screen_info.green_pos  = 0;
+       boot_params.screen_info.blue_pos   = 0;
+       boot_params.screen_info.rsvd_pos   = 0;
 }
 
 /* Save the VESA protected mode info */
 static void vesa_store_pm_info(void)
 {
-       u16 ax, bx, di, es;
+       struct biosregs ireg, oreg;
 
-       ax = 0x4f0a;
-       bx = di = 0;
-       asm("pushw %%es; "INT10"; movw %%es,%0; popw %%es"
-           : "=d" (es), "+a" (ax), "+b" (bx), "+D" (di)
-           : : "ecx", "esi");
+       initregs(&ireg);
+       ireg.ax = 0x4f0a;
+       intcall(0x10, &ireg, &oreg);
 
-       if (ax != 0x004f)
+       if (oreg.ax != 0x004f)
                return;
 
-       boot_params.screen_info.vesapm_seg = es;
-       boot_params.screen_info.vesapm_off = di;
+       boot_params.screen_info.vesapm_seg = oreg.es;
+       boot_params.screen_info.vesapm_off = oreg.di;
 }
 
 /*
@@ -252,7 +242,7 @@ static void vesa_store_mode_params_graphics(void)
 void vesa_store_edid(void)
 {
 #ifdef CONFIG_FIRMWARE_EDID
-       u16 ax, bx, cx, dx, di;
+       struct biosregs ireg, oreg;
 
        /* Apparently used as a nonsense token... */
        memset(&boot_params.edid_info, 0x13, sizeof boot_params.edid_info);
@@ -260,33 +250,26 @@ void vesa_store_edid(void)
        if (vginfo.version < 0x0200)
                return;         /* EDID requires VBE 2.0+ */
 
-       ax = 0x4f15;            /* VBE DDC */
-       bx = 0x0000;            /* Report DDC capabilities */
-       cx = 0;                 /* Controller 0 */
-       di = 0;                 /* ES:DI must be 0 by spec */
-
-       /* Note: The VBE DDC spec is different from the main VESA spec;
-          we genuinely have to assume all registers are destroyed here. */
-
-       asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es"
-           : "+a" (ax), "+b" (bx), "+c" (cx), "+D" (di)
-           : : "esi", "edx");
+       initregs(&ireg);
+       ireg.ax = 0x4f15;               /* VBE DDC */
+       /* ireg.bx = 0x0000; */         /* Report DDC capabilities */
+       /* ireg.cx = 0; */              /* Controller 0 */
+       ireg.es = 0;                    /* ES:DI must be 0 by spec */
+       intcall(0x10, &ireg, &oreg);
 
-       if (ax != 0x004f)
+       if (oreg.ax != 0x004f)
                return;         /* No EDID */
 
        /* BH = time in seconds to transfer EDD information */
        /* BL = DDC level supported */
 
-       ax = 0x4f15;            /* VBE DDC */
-       bx = 0x0001;            /* Read EDID */
-       cx = 0;                 /* Controller 0 */
-       dx = 0;                 /* EDID block number */
-       di =(size_t) &boot_params.edid_info; /* (ES:)Pointer to block */
-       asm(INT10
-           : "+a" (ax), "+b" (bx), "+d" (dx), "=m" (boot_params.edid_info),
-             "+c" (cx), "+D" (di)
-           : : "esi");
+       ireg.ax = 0x4f15;               /* VBE DDC */
+       ireg.bx = 0x0001;               /* Read EDID */
+       /* ireg.cx = 0; */              /* Controller 0 */
+       /* ireg.dx = 0; */              /* EDID block number */
+       ireg.es = ds();
+       ireg.di =(size_t)&boot_params.edid_info; /* (ES:)Pointer to block */
+       intcall(0x10, &ireg, &oreg);
 #endif /* CONFIG_FIRMWARE_EDID */
 }
 
index 9e0587a3776868e73b62b7def725997b6ffb7699..8f8d827e254d0b8cb392bf7fe95103059ac5ca89 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.
@@ -39,30 +40,30 @@ static __videocard video_vga;
 /* Set basic 80x25 mode */
 static u8 vga_set_basic_mode(void)
 {
+       struct biosregs ireg, oreg;
        u16 ax;
        u8 rows;
        u8 mode;
 
+       initregs(&ireg);
+
 #ifdef CONFIG_VIDEO_400_HACK
        if (adapter >= ADAPTER_VGA) {
-               asm volatile(INT10
-                            : : "a" (0x1202), "b" (0x0030)
-                            : "ecx", "edx", "esi", "edi");
+               ireg.ax = 0x1202;
+               ireg.bx = 0x0030;
+               intcall(0x10, &ireg, NULL);
        }
 #endif
 
        ax = 0x0f00;
-       asm volatile(INT10
-                    : "+a" (ax)
-                    : : "ebx", "ecx", "edx", "esi", "edi");
-
-       mode = (u8)ax;
+       intcall(0x10, &ireg, &oreg);
+       mode = oreg.al;
 
        set_fs(0);
        rows = rdfs8(0x484);    /* rows minus one */
 
 #ifndef CONFIG_VIDEO_400_HACK
-       if ((ax == 0x5003 || ax == 0x5007) &&
+       if ((oreg.ax == 0x5003 || oreg.ax == 0x5007) &&
            (rows == 0 || rows == 24))
                return mode;
 #endif
@@ -71,10 +72,8 @@ static u8 vga_set_basic_mode(void)
                mode = 3;
 
        /* Set the mode */
-       ax = mode;
-       asm volatile(INT10
-                    : "+a" (ax)
-                    : : "ebx", "ecx", "edx", "esi", "edi");
+       ireg.ax = mode;         /* AH=0: set mode */
+       intcall(0x10, &ireg, NULL);
        do_restore = 1;
        return mode;
 }
@@ -82,43 +81,69 @@ static u8 vga_set_basic_mode(void)
 static void vga_set_8font(void)
 {
        /* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */
+       struct biosregs ireg;
+
+       initregs(&ireg);
 
        /* Set 8x8 font */
-       asm volatile(INT10 : : "a" (0x1112), "b" (0));
+       ireg.ax = 0x1112;
+       /* ireg.bl = 0; */
+       intcall(0x10, &ireg, NULL);
 
        /* Use alternate print screen */
-       asm volatile(INT10 : : "a" (0x1200), "b" (0x20));
+       ireg.ax = 0x1200;
+       ireg.bl = 0x20;
+       intcall(0x10, &ireg, NULL);
 
        /* Turn off cursor emulation */
-       asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
+       ireg.ax = 0x1201;
+       ireg.bl = 0x34;
+       intcall(0x10, &ireg, NULL);
 
        /* Cursor is scan lines 6-7 */
-       asm volatile(INT10 : : "a" (0x0100), "c" (0x0607));
+       ireg.ax = 0x0100;
+       ireg.cx = 0x0607;
+       intcall(0x10, &ireg, NULL);
 }
 
 static void vga_set_14font(void)
 {
        /* Set 9x14 font - 80x28 on VGA */
+       struct biosregs ireg;
+
+       initregs(&ireg);
 
        /* Set 9x14 font */
-       asm volatile(INT10 : : "a" (0x1111), "b" (0));
+       ireg.ax = 0x1111;
+       /* ireg.bl = 0; */
+       intcall(0x10, &ireg, NULL);
 
        /* Turn off cursor emulation */
-       asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
+       ireg.ax = 0x1201;
+       ireg.bl = 0x34;
+       intcall(0x10, &ireg, NULL);
 
        /* Cursor is scan lines 11-12 */
-       asm volatile(INT10 : : "a" (0x0100), "c" (0x0b0c));
+       ireg.ax = 0x0100;
+       ireg.cx = 0x0b0c;
+       intcall(0x10, &ireg, NULL);
 }
 
 static void vga_set_80x43(void)
 {
        /* Set 80x43 mode on VGA (not EGA) */
+       struct biosregs ireg;
+
+       initregs(&ireg);
 
        /* Set 350 scans */
-       asm volatile(INT10 : : "a" (0x1201), "b" (0x30));
+       ireg.ax = 0x1201;
+       ireg.bl = 0x30;
+       intcall(0x10, &ireg, NULL);
 
        /* Reset video mode */
-       asm volatile(INT10 : : "a" (0x0003));
+       ireg.ax = 0x0003;
+       intcall(0x10, &ireg, NULL);
 
        vga_set_8font();
 }
@@ -225,8 +250,6 @@ static int vga_set_mode(struct mode_info *mode)
  */
 static int vga_probe(void)
 {
-       u16 ega_bx;
-
        static const char *card_name[] = {
                "CGA/MDA/HGC", "EGA", "VGA"
        };
@@ -240,26 +263,26 @@ static int vga_probe(void)
                sizeof(ega_modes)/sizeof(struct mode_info),
                sizeof(vga_modes)/sizeof(struct mode_info),
        };
-       u8 vga_flag;
 
-       asm(INT10
-           : "=b" (ega_bx)
-           : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */
-           : "ecx", "edx", "esi", "edi");
+       struct biosregs ireg, oreg;
+
+       initregs(&ireg);
+
+       ireg.ax = 0x1200;
+       ireg.bl = 0x10;         /* Check EGA/VGA */
+       intcall(0x10, &ireg, &oreg);
 
 #ifndef _WAKEUP
-       boot_params.screen_info.orig_video_ega_bx = ega_bx;
+       boot_params.screen_info.orig_video_ega_bx = oreg.bx;
 #endif
 
        /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */
-       if ((u8)ega_bx != 0x10) {
+       if (oreg.bl != 0x10) {
                /* EGA/VGA */
-               asm(INT10
-                   : "=a" (vga_flag)
-                   : "a" (0x1a00)
-                   : "ebx", "ecx", "edx", "esi", "edi");
+               ireg.ax = 0x1a00;
+               intcall(0x10, &ireg, &oreg);
 
-               if (vga_flag == 0x1a) {
+               if (oreg.al == 0x1a) {
                        adapter = ADAPTER_VGA;
 #ifndef _WAKEUP
                        boot_params.screen_info.orig_video_isVGA = 1;
index 3bef2c1febe936bd01f1b8d7d6b7d1eb5b1f9bb6..bad728b76fc2acff40b1e5052ae20b0e08ea5dc1 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.
 
 static void store_cursor_position(void)
 {
-       u16 curpos;
-       u16 ax, bx;
+       struct biosregs ireg, oreg;
 
-       ax = 0x0300;
-       bx = 0;
-       asm(INT10
-           : "=d" (curpos), "+a" (ax), "+b" (bx)
-           : : "ecx", "esi", "edi");
+       initregs(&ireg);
+       ireg.ah = 0x03;
+       intcall(0x10, &ireg, &oreg);
 
-       boot_params.screen_info.orig_x = curpos;
-       boot_params.screen_info.orig_y = curpos >> 8;
+       boot_params.screen_info.orig_x = oreg.dl;
+       boot_params.screen_info.orig_y = oreg.dh;
 }
 
 static void store_video_mode(void)
 {
-       u16 ax, page;
+       struct biosregs ireg, oreg;
 
        /* N.B.: the saving of the video page here is a bit silly,
           since we pretty much assume page 0 everywhere. */
-       ax = 0x0f00;
-       asm(INT10
-           : "+a" (ax), "=b" (page)
-           : : "ecx", "edx", "esi", "edi");
+       initregs(&ireg);
+       ireg.ah = 0x0f;
+       intcall(0x10, &ireg, &oreg);
 
        /* Not all BIOSes are clean with respect to the top bit */
-       boot_params.screen_info.orig_video_mode = ax & 0x7f;
-       boot_params.screen_info.orig_video_page = page >> 8;
+       boot_params.screen_info.orig_video_mode = oreg.al & 0x7f;
+       boot_params.screen_info.orig_video_page = oreg.bh;
 }
 
 /*
@@ -257,7 +254,7 @@ static void restore_screen(void)
        int y;
        addr_t dst = 0;
        u16 *src = saved.data;
-       u16 ax, bx, dx;
+       struct biosregs ireg;
 
        if (graphic_mode)
                return;         /* Can't restore onto a graphic mode */
@@ -296,12 +293,11 @@ static void restore_screen(void)
        }
 
        /* Restore cursor position */
-       ax = 0x0200;            /* Set cursor position */
-       bx = 0;                 /* Page number (<< 8) */
-       dx = (saved.cury << 8)+saved.curx;
-       asm volatile(INT10
-                    : "+a" (ax), "+b" (bx), "+d" (dx)
-                    : : "ecx", "esi", "edi");
+       initregs(&ireg);
+       ireg.ah = 0x02;         /* Set cursor position */
+       ireg.dh = saved.cury;
+       ireg.dl = saved.curx;
+       intcall(0x10, &ireg, NULL);
 }
 #else
 #define save_screen()          ((void)0)
index ee63f5d14461517ef96b89a6c644ac6c3a60a2f6..5bb174a997fc61a3609a0a41500192f4475e676a 100644 (file)
@@ -112,20 +112,6 @@ extern int force_x, force_y;       /* Don't query the BIOS for cols/rows */
 extern int do_restore;         /* Restore screen contents */
 extern int graphic_mode;       /* Graphics mode with linear frame buffer */
 
-/*
- * int $0x10 is notorious for touching registers it shouldn't.
- * gcc doesn't like %ebp being clobbered, so define it as a push/pop
- * sequence here.
- *
- * A number of systems, including the original PC can clobber %bp in
- * certain circumstances, like when scrolling.  There exists at least
- * one Trident video card which could clobber DS under a set of
- * circumstances that we are unlikely to encounter (scrolling when
- * using an extended graphics mode of more than 800x600 pixels), but
- * it's cheap insurance to deal with that here.
- */
-#define INT10 "pushl %%ebp; pushw %%ds; int $0x10; popw %%ds; popl %%ebp"
-
 /* Accessing VGA indexed registers */
 static inline u8 in_idx(u16 port, u8 index)
 {
index 235b81d0f6f2b1083c06cc46210df33141eb2b4b..edb992ebef92e2d95a8ce5d52d6f4ff33de91529 100644 (file)
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29-rc4
-# Tue Feb 24 15:50:58 2009
+# Linux kernel version: 2.6.30-rc2
+# Mon May 11 16:21:55 2009
 #
 # CONFIG_64BIT is not set
 CONFIG_X86_32=y
 # CONFIG_X86_64 is not set
 CONFIG_X86=y
+CONFIG_OUTPUT_FORMAT="elf32-i386"
 CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CMOS_UPDATE=y
@@ -33,6 +34,7 @@ CONFIG_ARCH_HAS_CPU_RELAX=y
 CONFIG_ARCH_HAS_DEFAULT_IDLE=y
 CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
 CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_HAVE_DYNAMIC_PER_CPU_AREA=y
 # CONFIG_HAVE_CPUMASK_OF_CPU_MAP is not set
 CONFIG_ARCH_HIBERNATION_POSSIBLE=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
@@ -40,15 +42,16 @@ CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_ARCH_POPULATES_NODE_MAP=y
 # CONFIG_AUDIT_ARCH is not set
 CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
 CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_PENDING_IRQ=y
-CONFIG_X86_SMP=y
 CONFIG_USE_GENERIC_SMP_HELPERS=y
 CONFIG_X86_32_SMP=y
 CONFIG_X86_HT=y
-CONFIG_X86_BIOS_REBOOT=y
 CONFIG_X86_TRAMPOLINE=y
+CONFIG_X86_32_LAZY_GS=y
 CONFIG_KTIME_SCALAR=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -60,10 +63,17 @@ CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_TASKSTATS=y
@@ -113,23 +123,26 @@ CONFIG_PID_NS=y
 CONFIG_NET_NS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 # CONFIG_EMBEDDED is not set
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_PCSPKR_PLATFORM=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
@@ -139,6 +152,7 @@ CONFIG_AIO=y
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_PCI_QUIRKS=y
 CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
@@ -154,6 +168,8 @@ CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -167,7 +183,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_STOP_MACHINE=y
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
-CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_BLK_DEV_BSG=y
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -194,12 +209,12 @@ CONFIG_HIGH_RES_TIMERS=y
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 CONFIG_SMP=y
 CONFIG_SPARSE_IRQ=y
-CONFIG_X86_FIND_SMP_CONFIG=y
 CONFIG_X86_MPPARSE=y
+# CONFIG_X86_BIGSMP is not set
+CONFIG_X86_EXTENDED_PLATFORM=y
 # CONFIG_X86_ELAN is not set
-# CONFIG_X86_GENERICARCH is not set
-# CONFIG_X86_VSMP is not set
 # CONFIG_X86_RDC321X is not set
+# CONFIG_X86_32_NON_STANDARD is not set
 CONFIG_SCHED_OMIT_FRAME_POINTER=y
 # CONFIG_PARAVIRT_GUEST is not set
 # CONFIG_MEMTEST is not set
@@ -230,8 +245,10 @@ CONFIG_M686=y
 # CONFIG_GENERIC_CPU is not set
 CONFIG_X86_GENERIC=y
 CONFIG_X86_CPU=y
+CONFIG_X86_L1_CACHE_BYTES=64
+CONFIG_X86_INTERNODE_CACHE_BYTES=64
 CONFIG_X86_CMPXCHG=y
-CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_X86_L1_CACHE_SHIFT=5
 CONFIG_X86_XADD=y
 # CONFIG_X86_PPRO_FENCE is not set
 CONFIG_X86_WP_WORKS_OK=y
@@ -247,7 +264,7 @@ CONFIG_X86_DEBUGCTLMSR=y
 CONFIG_CPU_SUP_INTEL=y
 CONFIG_CPU_SUP_CYRIX_32=y
 CONFIG_CPU_SUP_AMD=y
-CONFIG_CPU_SUP_CENTAUR_32=y
+CONFIG_CPU_SUP_CENTAUR=y
 CONFIG_CPU_SUP_TRANSMETA_32=y
 CONFIG_CPU_SUP_UMC_32=y
 CONFIG_X86_DS=y
@@ -279,6 +296,7 @@ CONFIG_MICROCODE_AMD=y
 CONFIG_MICROCODE_OLD_INTERFACE=y
 CONFIG_X86_MSR=y
 CONFIG_X86_CPUID=y
+# CONFIG_X86_CPU_DEBUG is not set
 # CONFIG_NOHIGHMEM is not set
 CONFIG_HIGHMEM4G=y
 # CONFIG_HIGHMEM64G is not set
@@ -302,6 +320,8 @@ CONFIG_ZONE_DMA_FLAG=1
 CONFIG_BOUNCE=y
 CONFIG_VIRT_TO_BUS=y
 CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
 CONFIG_HIGHPTE=y
 CONFIG_X86_CHECK_BIOS_CORRUPTION=y
 CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y
@@ -312,6 +332,7 @@ CONFIG_MTRR=y
 CONFIG_X86_PAT=y
 CONFIG_EFI=y
 CONFIG_SECCOMP=y
+# CONFIG_CC_STACKPROTECTOR is not set
 # CONFIG_HZ_100 is not set
 # CONFIG_HZ_250 is not set
 # CONFIG_HZ_300 is not set
@@ -322,8 +343,9 @@ CONFIG_KEXEC=y
 CONFIG_CRASH_DUMP=y
 # CONFIG_KEXEC_JUMP is not set
 CONFIG_PHYSICAL_START=0x1000000
-# CONFIG_RELOCATABLE is not set
-CONFIG_PHYSICAL_ALIGN=0x200000
+CONFIG_RELOCATABLE=y
+CONFIG_X86_NEED_RELOCS=y
+CONFIG_PHYSICAL_ALIGN=0x1000000
 CONFIG_HOTPLUG_CPU=y
 # CONFIG_COMPAT_VDSO is not set
 # CONFIG_CMDLINE_BOOL is not set
@@ -363,7 +385,6 @@ CONFIG_ACPI_THERMAL=y
 CONFIG_ACPI_BLACKLIST_YEAR=0
 # CONFIG_ACPI_DEBUG is not set
 # CONFIG_ACPI_PCI_SLOT is not set
-CONFIG_ACPI_SYSTEM=y
 CONFIG_X86_PM_TIMER=y
 CONFIG_ACPI_CONTAINER=y
 # CONFIG_ACPI_SBS is not set
@@ -425,6 +446,7 @@ CONFIG_PCI_BIOS=y
 CONFIG_PCI_DIRECT=y
 CONFIG_PCI_MMCONFIG=y
 CONFIG_PCI_DOMAINS=y
+# CONFIG_DMAR is not set
 CONFIG_PCIEPORTBUS=y
 # CONFIG_HOTPLUG_PCI_PCIE is not set
 CONFIG_PCIEAER=y
@@ -435,6 +457,7 @@ CONFIG_PCI_MSI=y
 # CONFIG_PCI_DEBUG is not set
 # CONFIG_PCI_STUB is not set
 CONFIG_HT_IRQ=y
+# CONFIG_PCI_IOV is not set
 CONFIG_ISA_DMA_API=y
 # CONFIG_ISA is not set
 # CONFIG_MCA is not set
@@ -481,7 +504,6 @@ CONFIG_NET=y
 #
 # Networking options
 #
-CONFIG_COMPAT_NET_DEV_OPS=y
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
@@ -639,6 +661,7 @@ CONFIG_LLC=y
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
 CONFIG_NET_SCHED=y
 
 #
@@ -696,6 +719,7 @@ CONFIG_NET_SCH_FIFO=y
 #
 # CONFIG_NET_PKTGEN is not set
 # CONFIG_NET_TCPPROBE is not set
+# CONFIG_NET_DROP_MONITOR is not set
 CONFIG_HAMRADIO=y
 
 #
@@ -706,12 +730,10 @@ CONFIG_HAMRADIO=y
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
 CONFIG_FIB_RULES=y
 CONFIG_WIRELESS=y
 CONFIG_CFG80211=y
 # CONFIG_CFG80211_REG_DEBUG is not set
-CONFIG_NL80211=y
 CONFIG_WIRELESS_OLD_REGULATORY=y
 CONFIG_WIRELESS_EXT=y
 CONFIG_WIRELESS_EXT_SYSFS=y
@@ -789,6 +811,7 @@ CONFIG_MISC_DEVICES=y
 # CONFIG_ICS932S401 is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
 # CONFIG_HP_ILO is not set
+# CONFIG_ISL29003 is not set
 # CONFIG_C2PORT is not set
 
 #
@@ -842,6 +865,7 @@ CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_LOWLEVEL is not set
 # CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
 # CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
 CONFIG_ATA=y
 # CONFIG_ATA_NONSTANDARD is not set
 CONFIG_ATA_ACPI=y
@@ -940,6 +964,7 @@ CONFIG_DM_ZERO=y
 CONFIG_MACINTOSH_DRIVERS=y
 CONFIG_MAC_EMUMOUSEBTN=y
 CONFIG_NETDEVICES=y
+CONFIG_COMPAT_NET_DEV_OPS=y
 # CONFIG_IFB is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
@@ -977,6 +1002,8 @@ CONFIG_MII=y
 CONFIG_NET_VENDOR_3COM=y
 # CONFIG_VORTEX is not set
 # CONFIG_TYPHOON is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 # CONFIG_TULIP is not set
@@ -1026,6 +1053,7 @@ CONFIG_E1000=y
 CONFIG_E1000E=y
 # CONFIG_IP1000 is not set
 # CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -1040,6 +1068,7 @@ CONFIG_BNX2=y
 # CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
 # CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
 # CONFIG_JME is not set
 CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
@@ -1049,6 +1078,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
 # CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
+# CONFIG_VXGE is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_NIU is not set
@@ -1058,6 +1088,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
 # CONFIG_BNX2X is not set
 # CONFIG_QLGE is not set
 # CONFIG_SFC is not set
+# CONFIG_BE2NET is not set
 CONFIG_TR=y
 # CONFIG_IBMOL is not set
 # CONFIG_IBMLS is not set
@@ -1073,8 +1104,8 @@ CONFIG_WLAN_80211=y
 # CONFIG_LIBERTAS is not set
 # CONFIG_LIBERTAS_THINFIRM is not set
 # CONFIG_AIRO is not set
-# CONFIG_HERMES is not set
 # CONFIG_ATMEL is not set
+# CONFIG_AT76C50X_USB is not set
 # CONFIG_AIRO_CS is not set
 # CONFIG_PCMCIA_WL3501 is not set
 # CONFIG_PRISM54 is not set
@@ -1084,21 +1115,21 @@ CONFIG_WLAN_80211=y
 # CONFIG_RTL8187 is not set
 # CONFIG_ADM8211 is not set
 # CONFIG_MAC80211_HWSIM is not set
+# CONFIG_MWL8K is not set
 # CONFIG_P54_COMMON is not set
 CONFIG_ATH5K=y
 # CONFIG_ATH5K_DEBUG is not set
 # CONFIG_ATH9K is not set
+# CONFIG_AR9170_USB is not set
 # CONFIG_IPW2100 is not set
 # CONFIG_IPW2200 is not set
-# CONFIG_IWLCORE is not set
-# CONFIG_IWLWIFI_LEDS is not set
-# CONFIG_IWLAGN is not set
-# CONFIG_IWL3945 is not set
+# CONFIG_IWLWIFI is not set
 # CONFIG_HOSTAP is not set
 # CONFIG_B43 is not set
 # CONFIG_B43LEGACY is not set
 # CONFIG_ZD1211RW is not set
 # CONFIG_RT2X00 is not set
+# CONFIG_HERMES is not set
 
 #
 # Enable WiMAX (Networking options) to see the WiMAX drivers
@@ -1209,6 +1240,8 @@ CONFIG_INPUT_TABLET=y
 # CONFIG_TABLET_USB_KBTAB is not set
 # CONFIG_TABLET_USB_WACOM is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
@@ -1303,6 +1336,7 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_IPMI_HANDLER is not set
 CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
 CONFIG_HW_RANDOM_INTEL=y
 CONFIG_HW_RANDOM_AMD=y
 CONFIG_HW_RANDOM_GEODE=y
@@ -1390,7 +1424,6 @@ CONFIG_I2C_I801=y
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_PCF8575 is not set
 # CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
@@ -1424,6 +1457,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_ADT7475 is not set
 # CONFIG_SENSORS_K8TEMP is not set
 # CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATK0110 is not set
 # CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_I5K_AMB is not set
@@ -1433,6 +1467,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_FSCHER is not set
 # CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_FSCHMD is not set
+# CONFIG_SENSORS_G760A is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_CORETEMP is not set
@@ -1448,11 +1483,14 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
 # CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_MAX6650 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_DME1737 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
@@ -1643,7 +1681,6 @@ CONFIG_FB_EFI=y
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_VT8623 is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_ARK is not set
 # CONFIG_FB_PM3 is not set
@@ -1652,6 +1689,7 @@ CONFIG_FB_EFI=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_METRONOME is not set
 # CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -1738,6 +1776,8 @@ CONFIG_SND_PCI=y
 # CONFIG_SND_INDIGO is not set
 # CONFIG_SND_INDIGOIO is not set
 # CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_INDIGOIOX is not set
+# CONFIG_SND_INDIGODJX is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1X is not set
 # CONFIG_SND_ENS1370 is not set
@@ -1811,15 +1851,17 @@ CONFIG_USB_HIDDEV=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
+# CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
+CONFIG_HID_KYE=y
 CONFIG_HID_GYRATION=y
+CONFIG_HID_KENSINGTON=y
 CONFIG_HID_LOGITECH=y
 CONFIG_LOGITECH_FF=y
 # CONFIG_LOGIRUMBLEPAD2_FF is not set
@@ -1885,11 +1927,11 @@ CONFIG_USB_PRINTER=y
 # CONFIG_USB_TMC is not set
 
 #
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
 #
 
 #
-# see USB_STORAGE Help for more information
+# also be needed; see USB_STORAGE Help for more info
 #
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -1931,7 +1973,6 @@ CONFIG_USB_LIBUSUAL=y
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
 # CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_FTDI_ELAN is not set
 # CONFIG_USB_APPLEDISPLAY is not set
@@ -1947,6 +1988,7 @@ CONFIG_USB_LIBUSUAL=y
 #
 # OTG and related infrastructure
 #
+# CONFIG_NOP_USB_XCEIV is not set
 # CONFIG_UWB is not set
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
@@ -1958,8 +2000,10 @@ CONFIG_LEDS_CLASS=y
 #
 # CONFIG_LEDS_ALIX2 is not set
 # CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_LP5521 is not set
 # CONFIG_LEDS_CLEVO_MAIL is not set
 # CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_BD2802 is not set
 
 #
 # LED Triggers
@@ -1969,6 +2013,10 @@ CONFIG_LEDS_TRIGGERS=y
 # CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
 # CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
 # CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
 # CONFIG_ACCESSIBILITY is not set
 # CONFIG_INFINIBAND is not set
 CONFIG_EDAC=y
@@ -2037,6 +2085,7 @@ CONFIG_DMADEVICES=y
 # DMA Devices
 #
 # CONFIG_INTEL_IOATDMA is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
 # CONFIG_STAGING is not set
 CONFIG_X86_PLATFORM_DEVICES=y
@@ -2071,6 +2120,7 @@ CONFIG_DMIID=y
 #
 # CONFIG_EXT2_FS is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
 CONFIG_EXT3_FS_SECURITY=y
@@ -2100,6 +2150,11 @@ CONFIG_AUTOFS4_FS=y
 # CONFIG_FUSE_FS is not set
 CONFIG_GENERIC_ACL=y
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -2151,6 +2206,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -2164,7 +2220,6 @@ CONFIG_NFS_ACL_SUPPORT=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 CONFIG_RPCSEC_GSS_KRB5=y
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -2251,6 +2306,7 @@ CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 # CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_DETECT_HUNG_TASK is not set
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
@@ -2266,6 +2322,7 @@ CONFIG_TIMER_STATS=y
 # CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_HIGHMEM is not set
 CONFIG_DEBUG_BUGVERBOSE=y
@@ -2289,13 +2346,19 @@ CONFIG_FRAME_POINTER=y
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
 CONFIG_USER_STACKTRACE_SUPPORT=y
+CONFIG_NOP_TRACER=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
 CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_HAVE_HW_BRANCH_TRACER=y
+CONFIG_HAVE_FTRACE_SYSCALLS=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -2305,13 +2368,21 @@ CONFIG_HAVE_HW_BRANCH_TRACER=y
 # CONFIG_SYSPROF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_FTRACE_SYSCALLS is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_POWER_TRACER is not set
 # CONFIG_STACK_TRACER is not set
 # CONFIG_HW_BRANCH_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_MMIOTRACE is not set
 CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -2321,7 +2392,6 @@ CONFIG_EARLY_PRINTK=y
 CONFIG_EARLY_PRINTK_DBGP=y
 CONFIG_DEBUG_STACKOVERFLOW=y
 CONFIG_DEBUG_STACK_USAGE=y
-# CONFIG_DEBUG_PAGEALLOC is not set
 # CONFIG_DEBUG_PER_CPU_MAPS is not set
 # CONFIG_X86_PTDUMP is not set
 CONFIG_DEBUG_RODATA=y
@@ -2329,7 +2399,7 @@ CONFIG_DEBUG_RODATA=y
 CONFIG_DEBUG_NX_TEST=m
 # CONFIG_4KSTACKS is not set
 CONFIG_DOUBLEFAULT=y
-# CONFIG_MMIOTRACE is not set
+CONFIG_HAVE_MMIOTRACE_SUPPORT=y
 CONFIG_IO_DELAY_TYPE_0X80=0
 CONFIG_IO_DELAY_TYPE_0XED=1
 CONFIG_IO_DELAY_TYPE_UDELAY=2
@@ -2365,6 +2435,8 @@ CONFIG_SECURITY_SELINUX_AVC_STATS=y
 CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
 # CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
 # CONFIG_SECURITY_SMACK is not set
+# CONFIG_SECURITY_TOMOYO is not set
+# CONFIG_IMA is not set
 CONFIG_CRYPTO=y
 
 #
@@ -2380,10 +2452,12 @@ CONFIG_CRYPTO_BLKCIPHER2=y
 CONFIG_CRYPTO_HASH=y
 CONFIG_CRYPTO_HASH2=y
 CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
 CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_MANAGER2=y
 # CONFIG_CRYPTO_GF128MUL is not set
 # CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
 # CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_AUTHENC=y
 # CONFIG_CRYPTO_TEST is not set
@@ -2456,6 +2530,7 @@ CONFIG_CRYPTO_DES=y
 # Compression
 #
 # CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
 
 #
@@ -2467,11 +2542,13 @@ CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_GEODE is not set
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
 CONFIG_HAVE_KVM=y
+CONFIG_HAVE_KVM_IRQCHIP=y
 CONFIG_VIRTUALIZATION=y
 # CONFIG_KVM is not set
 # CONFIG_LGUEST is not set
 # CONFIG_VIRTIO_PCI is not set
 # CONFIG_VIRTIO_BALLOON is not set
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
@@ -2489,7 +2566,10 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_AUDIT_GENERIC=y
 CONFIG_ZLIB_INFLATE=y
-CONFIG_PLIST=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 9fe5d212ab4cc8291e0c55ebdc619a57c85f2d64..cee1dd2e69b2e173c5218365312e73332652337f 100644 (file)
@@ -1,12 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29-rc4
-# Tue Feb 24 15:44:16 2009
+# Linux kernel version: 2.6.30-rc2
+# Mon May 11 16:22:00 2009
 #
 CONFIG_64BIT=y
 # CONFIG_X86_32 is not set
 CONFIG_X86_64=y
 CONFIG_X86=y
+CONFIG_OUTPUT_FORMAT="elf64-x86-64"
 CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CMOS_UPDATE=y
@@ -34,6 +35,7 @@ CONFIG_ARCH_HAS_CPU_RELAX=y
 CONFIG_ARCH_HAS_DEFAULT_IDLE=y
 CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
 CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_HAVE_DYNAMIC_PER_CPU_AREA=y
 CONFIG_HAVE_CPUMASK_OF_CPU_MAP=y
 CONFIG_ARCH_HIBERNATION_POSSIBLE=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
@@ -41,14 +43,14 @@ CONFIG_ZONE_DMA32=y
 CONFIG_ARCH_POPULATES_NODE_MAP=y
 CONFIG_AUDIT_ARCH=y
 CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
 CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_PENDING_IRQ=y
-CONFIG_X86_SMP=y
 CONFIG_USE_GENERIC_SMP_HELPERS=y
 CONFIG_X86_64_SMP=y
 CONFIG_X86_HT=y
-CONFIG_X86_BIOS_REBOOT=y
 CONFIG_X86_TRAMPOLINE=y
 # CONFIG_KTIME_SCALAR is not set
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -61,10 +63,17 @@ CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_TASKSTATS=y
@@ -114,23 +123,26 @@ CONFIG_PID_NS=y
 CONFIG_NET_NS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 # CONFIG_EMBEDDED is not set
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_PCSPKR_PLATFORM=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
@@ -140,6 +152,7 @@ CONFIG_AIO=y
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_PCI_QUIRKS=y
 CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
@@ -155,6 +168,8 @@ CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+# CONFIG_SLOW_WORK is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -167,7 +182,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_STOP_MACHINE=y
 CONFIG_BLOCK=y
-CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_BLK_DEV_BSG=y
 # CONFIG_BLK_DEV_INTEGRITY is not set
 CONFIG_BLOCK_COMPAT=y
@@ -195,12 +209,10 @@ CONFIG_HIGH_RES_TIMERS=y
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 CONFIG_SMP=y
 CONFIG_SPARSE_IRQ=y
-# CONFIG_NUMA_MIGRATE_IRQ_DESC is not set
-CONFIG_X86_FIND_SMP_CONFIG=y
 CONFIG_X86_MPPARSE=y
-# CONFIG_X86_ELAN is not set
-# CONFIG_X86_GENERICARCH is not set
+CONFIG_X86_EXTENDED_PLATFORM=y
 # CONFIG_X86_VSMP is not set
+# CONFIG_X86_UV is not set
 CONFIG_SCHED_OMIT_FRAME_POINTER=y
 # CONFIG_PARAVIRT_GUEST is not set
 # CONFIG_MEMTEST is not set
@@ -230,10 +242,10 @@ CONFIG_SCHED_OMIT_FRAME_POINTER=y
 # CONFIG_MCORE2 is not set
 CONFIG_GENERIC_CPU=y
 CONFIG_X86_CPU=y
-CONFIG_X86_L1_CACHE_BYTES=128
-CONFIG_X86_INTERNODE_CACHE_BYTES=128
+CONFIG_X86_L1_CACHE_BYTES=64
+CONFIG_X86_INTERNODE_CACHE_BYTES=64
 CONFIG_X86_CMPXCHG=y
-CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_X86_L1_CACHE_SHIFT=6
 CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_TSC=y
 CONFIG_X86_CMPXCHG64=y
@@ -242,7 +254,7 @@ CONFIG_X86_MINIMUM_CPU_FAMILY=64
 CONFIG_X86_DEBUGCTLMSR=y
 CONFIG_CPU_SUP_INTEL=y
 CONFIG_CPU_SUP_AMD=y
-CONFIG_CPU_SUP_CENTAUR_64=y
+CONFIG_CPU_SUP_CENTAUR=y
 CONFIG_X86_DS=y
 CONFIG_X86_PTRACE_BTS=y
 CONFIG_HPET_TIMER=y
@@ -269,6 +281,7 @@ CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
 CONFIG_X86_MCE=y
 CONFIG_X86_MCE_INTEL=y
 CONFIG_X86_MCE_AMD=y
+CONFIG_X86_MCE_THRESHOLD=y
 # CONFIG_I8K is not set
 CONFIG_MICROCODE=y
 CONFIG_MICROCODE_INTEL=y
@@ -276,6 +289,7 @@ CONFIG_MICROCODE_AMD=y
 CONFIG_MICROCODE_OLD_INTERFACE=y
 CONFIG_X86_MSR=y
 CONFIG_X86_CPUID=y
+# CONFIG_X86_CPU_DEBUG is not set
 CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
 CONFIG_DIRECT_GBPAGES=y
 CONFIG_NUMA=y
@@ -309,6 +323,8 @@ CONFIG_ZONE_DMA_FLAG=1
 CONFIG_BOUNCE=y
 CONFIG_VIRT_TO_BUS=y
 CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
 CONFIG_X86_CHECK_BIOS_CORRUPTION=y
 CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y
 CONFIG_X86_RESERVE_LOW_64K=y
@@ -317,6 +333,7 @@ CONFIG_MTRR=y
 CONFIG_X86_PAT=y
 CONFIG_EFI=y
 CONFIG_SECCOMP=y
+# CONFIG_CC_STACKPROTECTOR is not set
 # CONFIG_HZ_100 is not set
 # CONFIG_HZ_250 is not set
 # CONFIG_HZ_300 is not set
@@ -325,9 +342,10 @@ CONFIG_HZ=1000
 CONFIG_SCHED_HRTICK=y
 CONFIG_KEXEC=y
 CONFIG_CRASH_DUMP=y
+# CONFIG_KEXEC_JUMP is not set
 CONFIG_PHYSICAL_START=0x1000000
-# CONFIG_RELOCATABLE is not set
-CONFIG_PHYSICAL_ALIGN=0x200000
+CONFIG_RELOCATABLE=y
+CONFIG_PHYSICAL_ALIGN=0x1000000
 CONFIG_HOTPLUG_CPU=y
 # CONFIG_COMPAT_VDSO is not set
 # CONFIG_CMDLINE_BOOL is not set
@@ -370,7 +388,6 @@ CONFIG_ACPI_NUMA=y
 CONFIG_ACPI_BLACKLIST_YEAR=0
 # CONFIG_ACPI_DEBUG is not set
 # CONFIG_ACPI_PCI_SLOT is not set
-CONFIG_ACPI_SYSTEM=y
 CONFIG_X86_PM_TIMER=y
 CONFIG_ACPI_CONTAINER=y
 # CONFIG_ACPI_SBS is not set
@@ -436,6 +453,7 @@ CONFIG_PCI_MSI=y
 # CONFIG_PCI_DEBUG is not set
 # CONFIG_PCI_STUB is not set
 CONFIG_HT_IRQ=y
+# CONFIG_PCI_IOV is not set
 CONFIG_ISA_DMA_API=y
 CONFIG_K8_NB=y
 CONFIG_PCCARD=y
@@ -481,7 +499,6 @@ CONFIG_NET=y
 #
 # Networking options
 #
-CONFIG_COMPAT_NET_DEV_OPS=y
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
@@ -639,6 +656,7 @@ CONFIG_LLC=y
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
 CONFIG_NET_SCHED=y
 
 #
@@ -696,6 +714,7 @@ CONFIG_NET_SCH_FIFO=y
 #
 # CONFIG_NET_PKTGEN is not set
 # CONFIG_NET_TCPPROBE is not set
+# CONFIG_NET_DROP_MONITOR is not set
 CONFIG_HAMRADIO=y
 
 #
@@ -706,12 +725,10 @@ CONFIG_HAMRADIO=y
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
 CONFIG_FIB_RULES=y
 CONFIG_WIRELESS=y
 CONFIG_CFG80211=y
 # CONFIG_CFG80211_REG_DEBUG is not set
-CONFIG_NL80211=y
 CONFIG_WIRELESS_OLD_REGULATORY=y
 CONFIG_WIRELESS_EXT=y
 CONFIG_WIRELESS_EXT_SYSFS=y
@@ -788,9 +805,8 @@ CONFIG_MISC_DEVICES=y
 # CONFIG_TIFM_CORE is not set
 # CONFIG_ICS932S401 is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
-# CONFIG_SGI_XP is not set
 # CONFIG_HP_ILO is not set
-# CONFIG_SGI_GRU is not set
+# CONFIG_ISL29003 is not set
 # CONFIG_C2PORT is not set
 
 #
@@ -844,6 +860,7 @@ CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_LOWLEVEL is not set
 # CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
 # CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
 CONFIG_ATA=y
 # CONFIG_ATA_NONSTANDARD is not set
 CONFIG_ATA_ACPI=y
@@ -940,6 +957,7 @@ CONFIG_DM_ZERO=y
 CONFIG_MACINTOSH_DRIVERS=y
 CONFIG_MAC_EMUMOUSEBTN=y
 CONFIG_NETDEVICES=y
+CONFIG_COMPAT_NET_DEV_OPS=y
 # CONFIG_IFB is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
@@ -977,6 +995,8 @@ CONFIG_MII=y
 CONFIG_NET_VENDOR_3COM=y
 # CONFIG_VORTEX is not set
 # CONFIG_TYPHOON is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 # CONFIG_TULIP is not set
@@ -1026,6 +1046,7 @@ CONFIG_E1000=y
 # CONFIG_E1000E is not set
 # CONFIG_IP1000 is not set
 # CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -1040,6 +1061,7 @@ CONFIG_TIGON3=y
 # CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
 # CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
 # CONFIG_JME is not set
 CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
@@ -1049,6 +1071,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
 # CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
+# CONFIG_VXGE is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_NIU is not set
@@ -1058,6 +1081,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
 # CONFIG_BNX2X is not set
 # CONFIG_QLGE is not set
 # CONFIG_SFC is not set
+# CONFIG_BE2NET is not set
 CONFIG_TR=y
 # CONFIG_IBMOL is not set
 # CONFIG_3C359 is not set
@@ -1072,8 +1096,8 @@ CONFIG_WLAN_80211=y
 # CONFIG_LIBERTAS is not set
 # CONFIG_LIBERTAS_THINFIRM is not set
 # CONFIG_AIRO is not set
-# CONFIG_HERMES is not set
 # CONFIG_ATMEL is not set
+# CONFIG_AT76C50X_USB is not set
 # CONFIG_AIRO_CS is not set
 # CONFIG_PCMCIA_WL3501 is not set
 # CONFIG_PRISM54 is not set
@@ -1083,21 +1107,21 @@ CONFIG_WLAN_80211=y
 # CONFIG_RTL8187 is not set
 # CONFIG_ADM8211 is not set
 # CONFIG_MAC80211_HWSIM is not set
+# CONFIG_MWL8K is not set
 # CONFIG_P54_COMMON is not set
 CONFIG_ATH5K=y
 # CONFIG_ATH5K_DEBUG is not set
 # CONFIG_ATH9K is not set
+# CONFIG_AR9170_USB is not set
 # CONFIG_IPW2100 is not set
 # CONFIG_IPW2200 is not set
-# CONFIG_IWLCORE is not set
-# CONFIG_IWLWIFI_LEDS is not set
-# CONFIG_IWLAGN is not set
-# CONFIG_IWL3945 is not set
+# CONFIG_IWLWIFI is not set
 # CONFIG_HOSTAP is not set
 # CONFIG_B43 is not set
 # CONFIG_B43LEGACY is not set
 # CONFIG_ZD1211RW is not set
 # CONFIG_RT2X00 is not set
+# CONFIG_HERMES is not set
 
 #
 # Enable WiMAX (Networking options) to see the WiMAX drivers
@@ -1208,6 +1232,8 @@ CONFIG_INPUT_TABLET=y
 # CONFIG_TABLET_USB_KBTAB is not set
 # CONFIG_TABLET_USB_WACOM is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
@@ -1301,6 +1327,7 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_IPMI_HANDLER is not set
 CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
 # CONFIG_HW_RANDOM_INTEL is not set
 # CONFIG_HW_RANDOM_AMD is not set
 CONFIG_NVRAM=y
@@ -1382,7 +1409,6 @@ CONFIG_I2C_I801=y
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_PCF8575 is not set
 # CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
@@ -1416,6 +1442,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_ADT7475 is not set
 # CONFIG_SENSORS_K8TEMP is not set
 # CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATK0110 is not set
 # CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_I5K_AMB is not set
@@ -1425,6 +1452,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_FSCHER is not set
 # CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_FSCHMD is not set
+# CONFIG_SENSORS_G760A is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_CORETEMP is not set
@@ -1440,11 +1468,14 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
 # CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_MAX6650 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_DME1737 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
@@ -1635,6 +1666,7 @@ CONFIG_FB_EFI=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_METRONOME is not set
 # CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -1720,6 +1752,8 @@ CONFIG_SND_PCI=y
 # CONFIG_SND_INDIGO is not set
 # CONFIG_SND_INDIGOIO is not set
 # CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_INDIGOIOX is not set
+# CONFIG_SND_INDIGODJX is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1X is not set
 # CONFIG_SND_ENS1370 is not set
@@ -1792,15 +1826,17 @@ CONFIG_USB_HIDDEV=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
+# CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
+CONFIG_HID_KYE=y
 CONFIG_HID_GYRATION=y
+CONFIG_HID_KENSINGTON=y
 CONFIG_HID_LOGITECH=y
 CONFIG_LOGITECH_FF=y
 # CONFIG_LOGIRUMBLEPAD2_FF is not set
@@ -1866,11 +1902,11 @@ CONFIG_USB_PRINTER=y
 # CONFIG_USB_TMC is not set
 
 #
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
 #
 
 #
-# see USB_STORAGE Help for more information
+# also be needed; see USB_STORAGE Help for more info
 #
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -1912,7 +1948,6 @@ CONFIG_USB_LIBUSUAL=y
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
 # CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_FTDI_ELAN is not set
 # CONFIG_USB_APPLEDISPLAY is not set
@@ -1928,6 +1963,7 @@ CONFIG_USB_LIBUSUAL=y
 #
 # OTG and related infrastructure
 #
+# CONFIG_NOP_USB_XCEIV is not set
 # CONFIG_UWB is not set
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
@@ -1939,8 +1975,10 @@ CONFIG_LEDS_CLASS=y
 #
 # CONFIG_LEDS_ALIX2 is not set
 # CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_LP5521 is not set
 # CONFIG_LEDS_CLEVO_MAIL is not set
 # CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_BD2802 is not set
 
 #
 # LED Triggers
@@ -1950,6 +1988,10 @@ CONFIG_LEDS_TRIGGERS=y
 # CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
 # CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
 # CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
 # CONFIG_ACCESSIBILITY is not set
 # CONFIG_INFINIBAND is not set
 CONFIG_EDAC=y
@@ -2018,6 +2060,7 @@ CONFIG_DMADEVICES=y
 # DMA Devices
 #
 # CONFIG_INTEL_IOATDMA is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
 # CONFIG_STAGING is not set
 CONFIG_X86_PLATFORM_DEVICES=y
@@ -2051,6 +2094,7 @@ CONFIG_DMIID=y
 #
 # CONFIG_EXT2_FS is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
 CONFIG_EXT3_FS_SECURITY=y
@@ -2081,6 +2125,11 @@ CONFIG_AUTOFS4_FS=y
 # CONFIG_FUSE_FS is not set
 CONFIG_GENERIC_ACL=y
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -2132,6 +2181,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -2145,7 +2195,6 @@ CONFIG_NFS_ACL_SUPPORT=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 CONFIG_RPCSEC_GSS_KRB5=y
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -2232,6 +2281,7 @@ CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 # CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_DETECT_HUNG_TASK is not set
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
@@ -2247,6 +2297,7 @@ CONFIG_TIMER_STATS=y
 # CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
@@ -2269,13 +2320,19 @@ CONFIG_FRAME_POINTER=y
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
 CONFIG_USER_STACKTRACE_SUPPORT=y
+CONFIG_NOP_TRACER=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
 CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_HAVE_HW_BRANCH_TRACER=y
+CONFIG_HAVE_FTRACE_SYSCALLS=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -2285,13 +2342,21 @@ CONFIG_HAVE_HW_BRANCH_TRACER=y
 # CONFIG_SYSPROF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_FTRACE_SYSCALLS is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_POWER_TRACER is not set
 # CONFIG_STACK_TRACER is not set
 # CONFIG_HW_BRANCH_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_MMIOTRACE is not set
 CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -2301,14 +2366,13 @@ CONFIG_EARLY_PRINTK=y
 CONFIG_EARLY_PRINTK_DBGP=y
 CONFIG_DEBUG_STACKOVERFLOW=y
 CONFIG_DEBUG_STACK_USAGE=y
-# CONFIG_DEBUG_PAGEALLOC is not set
 # CONFIG_DEBUG_PER_CPU_MAPS is not set
 # CONFIG_X86_PTDUMP is not set
 CONFIG_DEBUG_RODATA=y
 # CONFIG_DEBUG_RODATA_TEST is not set
 CONFIG_DEBUG_NX_TEST=m
 # CONFIG_IOMMU_DEBUG is not set
-# CONFIG_MMIOTRACE is not set
+CONFIG_HAVE_MMIOTRACE_SUPPORT=y
 CONFIG_IO_DELAY_TYPE_0X80=0
 CONFIG_IO_DELAY_TYPE_0XED=1
 CONFIG_IO_DELAY_TYPE_UDELAY=2
@@ -2344,6 +2408,8 @@ CONFIG_SECURITY_SELINUX_AVC_STATS=y
 CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
 # CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
 # CONFIG_SECURITY_SMACK is not set
+# CONFIG_SECURITY_TOMOYO is not set
+# CONFIG_IMA is not set
 CONFIG_CRYPTO=y
 
 #
@@ -2359,10 +2425,12 @@ CONFIG_CRYPTO_BLKCIPHER2=y
 CONFIG_CRYPTO_HASH=y
 CONFIG_CRYPTO_HASH2=y
 CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
 CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_MANAGER2=y
 # CONFIG_CRYPTO_GF128MUL is not set
 # CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
 # CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_AUTHENC=y
 # CONFIG_CRYPTO_TEST is not set
@@ -2414,6 +2482,7 @@ CONFIG_CRYPTO_SHA1=y
 #
 CONFIG_CRYPTO_AES=y
 # CONFIG_CRYPTO_AES_X86_64 is not set
+# CONFIG_CRYPTO_AES_NI_INTEL is not set
 # CONFIG_CRYPTO_ANUBIS is not set
 CONFIG_CRYPTO_ARC4=y
 # CONFIG_CRYPTO_BLOWFISH is not set
@@ -2435,6 +2504,7 @@ CONFIG_CRYPTO_DES=y
 # Compression
 #
 # CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
 
 #
@@ -2444,10 +2514,12 @@ CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
 CONFIG_HAVE_KVM=y
+CONFIG_HAVE_KVM_IRQCHIP=y
 CONFIG_VIRTUALIZATION=y
 # CONFIG_KVM is not set
 # CONFIG_VIRTIO_PCI is not set
 # CONFIG_VIRTIO_BALLOON is not set
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
@@ -2464,7 +2536,10 @@ CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
-CONFIG_PLIST=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index a505202086e8741a916e696ccfb664d3f3e0f8ef..dcef387ddc36a87cb78554784d02e91808e70fb0 100644 (file)
@@ -830,4 +830,5 @@ ia32_sys_call_table:
        .quad sys_inotify_init1
        .quad compat_sys_preadv
        .quad compat_sys_pwritev
+       .quad compat_sys_rt_tgsigqueueinfo      /* 335 */
 ia32_syscall_end:
index f6aa18eadf71717d9e86c53ac3719776fa035969..1a37bcdc8606c0ccefaa73026c2188a8235b1a24 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/types.h>
 #include <linux/stddef.h>
+#include <linux/stringify.h>
 #include <asm/asm.h>
 
 /*
@@ -74,6 +75,22 @@ static inline void alternatives_smp_switch(int smp) {}
 
 const unsigned char *const *find_nop_table(void);
 
+/* alternative assembly primitive: */
+#define ALTERNATIVE(oldinstr, newinstr, feature)                       \
+                                                                       \
+      "661:\n\t" oldinstr "\n662:\n"                                   \
+      ".section .altinstructions,\"a\"\n"                              \
+      _ASM_ALIGN "\n"                                                  \
+      _ASM_PTR "661b\n"                                /* label           */   \
+      _ASM_PTR "663f\n"                                /* new instruction */   \
+      "         .byte " __stringify(feature) "\n"      /* feature bit     */   \
+      "         .byte 662b-661b\n"                     /* sourcelen       */   \
+      "         .byte 664f-663f\n"                     /* replacementlen  */   \
+      ".previous\n"                                                    \
+      ".section .altinstr_replacement, \"ax\"\n"                       \
+      "663:\n\t" newinstr "\n664:\n"           /* replacement     */   \
+      ".previous"
+
 /*
  * Alternative instructions for different CPU types or capabilities.
  *
@@ -87,18 +104,7 @@ const unsigned char *const *find_nop_table(void);
  * without volatile and memory clobber.
  */
 #define alternative(oldinstr, newinstr, feature)                       \
-       asm volatile ("661:\n\t" oldinstr "\n662:\n"                    \
-                     ".section .altinstructions,\"a\"\n"               \
-                     _ASM_ALIGN "\n"                                   \
-                     _ASM_PTR "661b\n"         /* label */             \
-                     _ASM_PTR "663f\n"         /* new instruction */   \
-                     "  .byte %c0\n"           /* feature bit */       \
-                     "  .byte 662b-661b\n"     /* sourcelen */         \
-                     "  .byte 664f-663f\n"     /* replacementlen */    \
-                     ".previous\n"                                     \
-                     ".section .altinstr_replacement,\"ax\"\n"         \
-                     "663:\n\t" newinstr "\n664:\n"  /* replacement */ \
-                     ".previous" :: "i" (feature) : "memory")
+       asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory")
 
 /*
  * Alternative inline assembly with input.
@@ -109,35 +115,16 @@ const unsigned char *const *find_nop_table(void);
  * Best is to use constraints that are fixed size (like (%1) ... "r")
  * If you use variable sized constraints like "m" or "g" in the
  * replacement make sure to pad to the worst case length.
+ * Leaving an unused argument 0 to keep API compatibility.
  */
 #define alternative_input(oldinstr, newinstr, feature, input...)       \
-       asm volatile ("661:\n\t" oldinstr "\n662:\n"                    \
-                     ".section .altinstructions,\"a\"\n"               \
-                     _ASM_ALIGN "\n"                                   \
-                     _ASM_PTR "661b\n"         /* label */             \
-                     _ASM_PTR "663f\n"         /* new instruction */   \
-                     "  .byte %c0\n"           /* feature bit */       \
-                     "  .byte 662b-661b\n"     /* sourcelen */         \
-                     "  .byte 664f-663f\n"     /* replacementlen */    \
-                     ".previous\n"                                     \
-                     ".section .altinstr_replacement,\"ax\"\n"         \
-                     "663:\n\t" newinstr "\n664:\n"  /* replacement */ \
-                     ".previous" :: "i" (feature), ##input)
+       asm volatile (ALTERNATIVE(oldinstr, newinstr, feature)          \
+               : : "i" (0), ## input)
 
 /* Like alternative_input, but with a single output argument */
 #define alternative_io(oldinstr, newinstr, feature, output, input...)  \
-       asm volatile ("661:\n\t" oldinstr "\n662:\n"                    \
-                     ".section .altinstructions,\"a\"\n"               \
-                     _ASM_ALIGN "\n"                                   \
-                     _ASM_PTR "661b\n"         /* label */             \
-                     _ASM_PTR "663f\n"         /* new instruction */   \
-                     "  .byte %c[feat]\n"      /* feature bit */       \
-                     "  .byte 662b-661b\n"     /* sourcelen */         \
-                     "  .byte 664f-663f\n"     /* replacementlen */    \
-                     ".previous\n"                                     \
-                     ".section .altinstr_replacement,\"ax\"\n"         \
-                     "663:\n\t" newinstr "\n664:\n"  /* replacement */ \
-                     ".previous" : output : [feat] "i" (feature), ##input)
+       asm volatile (ALTERNATIVE(oldinstr, newinstr, feature)          \
+               : output : "i" (0), ## input)
 
 /*
  * use this macro(s) if you need more than one output parameter
index f712344329bc7a6929a38f8e0e968bd1166e4c9e..262e02820049aa8cc92dca18e83afdcbb829a71c 100644 (file)
@@ -27,6 +27,8 @@ extern int amd_iommu_init(void);
 extern int amd_iommu_init_dma_ops(void);
 extern void amd_iommu_detect(void);
 extern irqreturn_t amd_iommu_int_handler(int irq, void *data);
+extern void amd_iommu_flush_all_domains(void);
+extern void amd_iommu_flush_all_devices(void);
 #else
 static inline int amd_iommu_init(void) { return -ENODEV; }
 static inline void amd_iommu_detect(void) { }
index 95c8cd9d22b54401fc8de9cf734512126b34a05f..0c878caaa0a23cda2a83a0ab9bb9ef3620bf8fad 100644 (file)
 #define PD_DMA_OPS_MASK                (1UL << 0) /* domain used for dma_ops */
 #define PD_DEFAULT_MASK                (1UL << 1) /* domain is a default dma_ops
                                              domain for an IOMMU */
+extern bool amd_iommu_dump;
+#define DUMP_printk(format, arg...)                                    \
+       do {                                                            \
+               if (amd_iommu_dump)                                             \
+                       printk(KERN_INFO "AMD IOMMU: " format, ## arg); \
+       } while(0);
+
+/*
+ * Make iterating over all IOMMUs easier
+ */
+#define for_each_iommu(iommu) \
+       list_for_each_entry((iommu), &amd_iommu_list, list)
+#define for_each_iommu_safe(iommu, next) \
+       list_for_each_entry_safe((iommu), (next), &amd_iommu_list, list)
+
+#define APERTURE_RANGE_SHIFT   27      /* 128 MB */
+#define APERTURE_RANGE_SIZE    (1ULL << APERTURE_RANGE_SHIFT)
+#define APERTURE_RANGE_PAGES   (APERTURE_RANGE_SIZE >> PAGE_SHIFT)
+#define APERTURE_MAX_RANGES    32      /* allows 4GB of DMA address space */
+#define APERTURE_RANGE_INDEX(a)        ((a) >> APERTURE_RANGE_SHIFT)
+#define APERTURE_PAGE_INDEX(a) (((a) >> 21) & 0x3fULL)
 
 /*
  * This structure contains generic data for  IOMMU protection domains
@@ -209,6 +230,26 @@ struct protection_domain {
        void *priv;             /* private data */
 };
 
+/*
+ * For dynamic growth the aperture size is split into ranges of 128MB of
+ * DMA address space each. This struct represents one such range.
+ */
+struct aperture_range {
+
+       /* address allocation bitmap */
+       unsigned long *bitmap;
+
+       /*
+        * Array of PTE pages for the aperture. In this array we save all the
+        * leaf pages of the domain page table used for the aperture. This way
+        * we don't need to walk the page table to find a specific PTE. We can
+        * just calculate its address in constant time.
+        */
+       u64 *pte_pages[64];
+
+       unsigned long offset;
+};
+
 /*
  * Data container for a dma_ops specific protection domain
  */
@@ -222,18 +263,10 @@ struct dma_ops_domain {
        unsigned long aperture_size;
 
        /* address we start to search for free addresses */
-       unsigned long next_bit;
-
-       /* address allocation bitmap */
-       unsigned long *bitmap;
+       unsigned long next_address;
 
-       /*
-        * Array of PTE pages for the aperture. In this array we save all the
-        * leaf pages of the domain page table used for the aperture. This way
-        * we don't need to walk the page table to find a specific PTE. We can
-        * just calculate its address in constant time.
-        */
-       u64 **pte_pages;
+       /* address space relevant data */
+       struct aperture_range *aperture[APERTURE_MAX_RANGES];
 
        /* This will be set to true when TLB needs to be flushed */
        bool need_flush;
index 42f2f83774224fb7897bf848fc6b84c4bce87380..bb7d47925847c585ee7e9e66f6f2e8652b5ab753 100644 (file)
@@ -107,8 +107,7 @@ extern u32 native_safe_apic_wait_icr_idle(void);
 extern void native_apic_icr_write(u32 low, u32 id);
 extern u64 native_apic_icr_read(void);
 
-#define EIM_8BIT_APIC_ID       0
-#define EIM_32BIT_APIC_ID      1
+extern int x2apic_mode;
 
 #ifdef CONFIG_X86_X2APIC
 /*
@@ -166,10 +165,9 @@ static inline u64 native_x2apic_icr_read(void)
        return val;
 }
 
-extern int x2apic, x2apic_phys;
+extern int x2apic_phys;
 extern void check_x2apic(void);
 extern void enable_x2apic(void);
-extern void enable_IR_x2apic(void);
 extern void x2apic_icr_write(u32 low, u32 id);
 static inline int x2apic_enabled(void)
 {
@@ -183,6 +181,8 @@ static inline int x2apic_enabled(void)
                return 1;
        return 0;
 }
+
+#define x2apic_supported()     (cpu_has_x2apic)
 #else
 static inline void check_x2apic(void)
 {
@@ -190,28 +190,20 @@ static inline void check_x2apic(void)
 static inline void enable_x2apic(void)
 {
 }
-static inline void enable_IR_x2apic(void)
-{
-}
 static inline int x2apic_enabled(void)
 {
        return 0;
 }
 
-#define        x2apic  0
-
+#define        x2apic_preenabled 0
+#define        x2apic_supported()      0
 #endif
 
-extern int get_physical_broadcast(void);
+extern void enable_IR_x2apic(void);
 
-#ifdef CONFIG_X86_X2APIC
-static inline void ack_x2APIC_irq(void)
-{
-       /* Docs say use 0 for future compatibility */
-       native_apic_msr_write(APIC_EOI, 0);
-}
-#endif
+extern int get_physical_broadcast(void);
 
+extern void apic_disable(void);
 extern int lapic_get_maxlvt(void);
 extern void clear_local_APIC(void);
 extern void connect_bsp_APIC(void);
@@ -252,7 +244,7 @@ static inline void lapic_shutdown(void) { }
 #define local_apic_timer_c2_ok         1
 static inline void init_apic_mappings(void) { }
 static inline void disable_local_APIC(void) { }
-
+static inline void apic_disable(void) { }
 #endif /* !CONFIG_X86_LOCAL_APIC */
 
 #ifdef CONFIG_X86_64
@@ -410,7 +402,7 @@ static inline unsigned default_get_apic_id(unsigned long x)
 {
        unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR));
 
-       if (APIC_XAPIC(ver))
+       if (APIC_XAPIC(ver) || boot_cpu_has(X86_FEATURE_EXTD_APICID))
                return (x >> 24) & 0xFF;
        else
                return (x >> 24) & 0x0F;
@@ -478,6 +470,9 @@ static inline unsigned int read_apic_id(void)
 extern void default_setup_apic_routing(void);
 
 #ifdef CONFIG_X86_32
+
+extern struct apic apic_default;
+
 /*
  * Set up the logical destination ID.
  *
index bc9514fb3b13f70d75b11f037546eca8e43d07fd..7ddb36ab933b97b7757c0df30732d31d40404c19 100644 (file)
@@ -22,6 +22,7 @@
 #  define      APIC_INTEGRATED(x)      (1)
 #endif
 #define                APIC_XAPIC(x)           ((x) >= 0x14)
+#define                APIC_EXT_SPACE(x)       ((x) & 0x80000000)
 #define        APIC_TASKPRI    0x80
 #define                APIC_TPRI_MASK          0xFFu
 #define        APIC_ARBPRI     0x90
 #define                APIC_TDR_DIV_32         0x8
 #define                APIC_TDR_DIV_64         0x9
 #define                APIC_TDR_DIV_128        0xA
-#define        APIC_EILVT0     0x500
+#define        APIC_EFEAT      0x400
+#define        APIC_ECTRL      0x410
+#define APIC_EILVTn(n) (0x500 + 0x10 * n)
 #define                APIC_EILVT_NR_AMD_K8    1       /* # of extended interrupts */
 #define                APIC_EILVT_NR_AMD_10H   4
 #define                APIC_EILVT_LVTOFF(x)    (((x) >> 4) & 0xF)
 #define                APIC_EILVT_MSG_NMI      0x4
 #define                APIC_EILVT_MSG_EXT      0x7
 #define                APIC_EILVT_MASKED       (1 << 16)
-#define        APIC_EILVT1     0x510
-#define        APIC_EILVT2     0x520
-#define        APIC_EILVT3     0x530
 
 #define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
 #define APIC_BASE_MSR  0x800
index 6ba23dd9fc9216de96b9cb52d1954b9bb7ae2b99..418e632d4a801aa8e86f565afeae59659d6500a0 100644 (file)
@@ -8,11 +8,26 @@
 
 #ifdef __KERNEL__
 
+#include <asm/page_types.h>
+
 /* Physical address where kernel should be loaded. */
 #define LOAD_PHYSICAL_ADDR ((CONFIG_PHYSICAL_START \
                                + (CONFIG_PHYSICAL_ALIGN - 1)) \
                                & ~(CONFIG_PHYSICAL_ALIGN - 1))
 
+/* Minimum kernel alignment, as a power of two */
+#ifdef CONFIG_x86_64
+#define MIN_KERNEL_ALIGN_LG2   PMD_SHIFT
+#else
+#define MIN_KERNEL_ALIGN_LG2   (PAGE_SHIFT+1)
+#endif
+#define MIN_KERNEL_ALIGN       (_AC(1, UL) << MIN_KERNEL_ALIGN_LG2)
+
+#if (CONFIG_PHYSICAL_ALIGN & (CONFIG_PHYSICAL_ALIGN-1)) || \
+       (CONFIG_PHYSICAL_ALIGN < (_AC(1, UL) << MIN_KERNEL_ALIGN_LG2))
+#error "Invalid value for CONFIG_PHYSICAL_ALIGN"
+#endif
+
 #ifdef CONFIG_KERNEL_BZIP2
 #define BOOT_HEAP_SIZE             0x400000
 #else /* !CONFIG_KERNEL_BZIP2 */
index 433adaebf9b631f108399a3d27f660ff61a0369b..1724e8de317c59518daebdb305f75b23bb4fcaf6 100644 (file)
@@ -50,7 +50,8 @@ struct setup_header {
        __u32   ramdisk_size;
        __u32   bootsect_kludge;
        __u16   heap_end_ptr;
-       __u16   _pad1;
+       __u8    ext_loader_ver;
+       __u8    ext_loader_type;
        __u32   cmd_line_ptr;
        __u32   initrd_addr_max;
        __u32   kernel_alignment;
index 222802029fa6c43b504959401236d559991deba0..d96c1ee3a95cce1ec7fdf48a1fe5269bba58d32f 100644 (file)
@@ -86,105 +86,7 @@ enum cpu_file_bit {
        CPU_VALUE_BIT,                          /* value                */
 };
 
-#define        CPU_FILE_VALUE                  (1 << CPU_VALUE_BIT)
-
-/*
- * DisplayFamily_DisplayModel  Processor Families/Processor Number Series
- * --------------------------  ------------------------------------------
- * 05_01, 05_02, 05_04         Pentium, Pentium with MMX
- *
- * 06_01                       Pentium Pro
- * 06_03, 06_05                        Pentium II Xeon, Pentium II
- * 06_07, 06_08, 06_0A, 06_0B  Pentium III Xeon, Pentum III
- *
- * 06_09, 060D                 Pentium M
- *
- * 06_0E                       Core Duo, Core Solo
- *
- * 06_0F                       Xeon 3000, 3200, 5100, 5300, 7300 series,
- *                             Core 2 Quad, Core 2 Extreme, Core 2 Duo,
- *                             Pentium dual-core
- * 06_17                       Xeon 5200, 5400 series, Core 2 Quad Q9650
- *
- * 06_1C                       Atom
- *
- * 0F_00, 0F_01, 0F_02         Xeon, Xeon MP, Pentium 4
- * 0F_03, 0F_04                        Xeon, Xeon MP, Pentium 4, Pentium D
- *
- * 0F_06                       Xeon 7100, 5000 Series, Xeon MP,
- *                             Pentium 4, Pentium D
- */
-
-/* Register processors bits */
-enum cpu_processor_bit {
-       CPU_NONE,
-/* Intel */
-       CPU_INTEL_PENTIUM_BIT,
-       CPU_INTEL_P6_BIT,
-       CPU_INTEL_PENTIUM_M_BIT,
-       CPU_INTEL_CORE_BIT,
-       CPU_INTEL_CORE2_BIT,
-       CPU_INTEL_ATOM_BIT,
-       CPU_INTEL_XEON_P4_BIT,
-       CPU_INTEL_XEON_MP_BIT,
-/* AMD */
-       CPU_AMD_K6_BIT,
-       CPU_AMD_K7_BIT,
-       CPU_AMD_K8_BIT,
-       CPU_AMD_0F_BIT,
-       CPU_AMD_10_BIT,
-       CPU_AMD_11_BIT,
-};
-
-#define        CPU_INTEL_PENTIUM       (1 << CPU_INTEL_PENTIUM_BIT)
-#define        CPU_INTEL_P6            (1 << CPU_INTEL_P6_BIT)
-#define        CPU_INTEL_PENTIUM_M     (1 << CPU_INTEL_PENTIUM_M_BIT)
-#define        CPU_INTEL_CORE          (1 << CPU_INTEL_CORE_BIT)
-#define        CPU_INTEL_CORE2         (1 << CPU_INTEL_CORE2_BIT)
-#define        CPU_INTEL_ATOM          (1 << CPU_INTEL_ATOM_BIT)
-#define        CPU_INTEL_XEON_P4       (1 << CPU_INTEL_XEON_P4_BIT)
-#define        CPU_INTEL_XEON_MP       (1 << CPU_INTEL_XEON_MP_BIT)
-
-#define        CPU_INTEL_PX            (CPU_INTEL_P6 | CPU_INTEL_PENTIUM_M)
-#define        CPU_INTEL_COREX         (CPU_INTEL_CORE | CPU_INTEL_CORE2)
-#define        CPU_INTEL_XEON          (CPU_INTEL_XEON_P4 | CPU_INTEL_XEON_MP)
-#define        CPU_CO_AT               (CPU_INTEL_CORE | CPU_INTEL_ATOM)
-#define        CPU_C2_AT               (CPU_INTEL_CORE2 | CPU_INTEL_ATOM)
-#define        CPU_CX_AT               (CPU_INTEL_COREX | CPU_INTEL_ATOM)
-#define        CPU_CX_XE               (CPU_INTEL_COREX | CPU_INTEL_XEON)
-#define        CPU_P6_XE               (CPU_INTEL_P6 | CPU_INTEL_XEON)
-#define        CPU_PM_CO_AT            (CPU_INTEL_PENTIUM_M | CPU_CO_AT)
-#define        CPU_C2_AT_XE            (CPU_C2_AT | CPU_INTEL_XEON)
-#define        CPU_CX_AT_XE            (CPU_CX_AT | CPU_INTEL_XEON)
-#define        CPU_P6_CX_AT            (CPU_INTEL_P6 | CPU_CX_AT)
-#define        CPU_P6_CX_XE            (CPU_P6_XE | CPU_INTEL_COREX)
-#define        CPU_P6_CX_AT_XE         (CPU_INTEL_P6 | CPU_CX_AT_XE)
-#define        CPU_PM_CX_AT_XE         (CPU_INTEL_PENTIUM_M | CPU_CX_AT_XE)
-#define        CPU_PM_CX_AT            (CPU_INTEL_PENTIUM_M | CPU_CX_AT)
-#define        CPU_PM_CX_XE            (CPU_INTEL_PENTIUM_M | CPU_CX_XE)
-#define        CPU_PX_CX_AT            (CPU_INTEL_PX | CPU_CX_AT)
-#define        CPU_PX_CX_AT_XE         (CPU_INTEL_PX | CPU_CX_AT_XE)
-
-/* Select all supported Intel CPUs */
-#define        CPU_INTEL_ALL           (CPU_INTEL_PENTIUM | CPU_PX_CX_AT_XE)
-
-#define        CPU_AMD_K6              (1 << CPU_AMD_K6_BIT)
-#define        CPU_AMD_K7              (1 << CPU_AMD_K7_BIT)
-#define        CPU_AMD_K8              (1 << CPU_AMD_K8_BIT)
-#define        CPU_AMD_0F              (1 << CPU_AMD_0F_BIT)
-#define        CPU_AMD_10              (1 << CPU_AMD_10_BIT)
-#define        CPU_AMD_11              (1 << CPU_AMD_11_BIT)
-
-#define        CPU_K10_PLUS            (CPU_AMD_10 | CPU_AMD_11)
-#define        CPU_K0F_PLUS            (CPU_AMD_0F | CPU_K10_PLUS)
-#define        CPU_K8_PLUS             (CPU_AMD_K8 | CPU_K0F_PLUS)
-#define        CPU_K7_PLUS             (CPU_AMD_K7 | CPU_K8_PLUS)
-
-/* Select all supported AMD CPUs */
-#define        CPU_AMD_ALL             (CPU_AMD_K6 | CPU_K7_PLUS)
-
-/* Select all supported CPUs */
-#define        CPU_ALL                 (CPU_INTEL_ALL | CPU_AMD_ALL)
+#define        CPU_FILE_VALUE          (1 << CPU_VALUE_BIT)
 
 #define MAX_CPU_FILES          512
 
@@ -220,7 +122,6 @@ struct cpu_debug_range {
        unsigned                min;            /* Register range min   */
        unsigned                max;            /* Register range max   */
        unsigned                flag;           /* Supported flags      */
-       unsigned                model;          /* Supported models     */
 };
 
 #endif /* _ASM_X86_CPU_DEBUG_H */
index bb83b1c397aad8d05251db9dcd71880b1967b1f4..4a28d22d479362ccf3a5bedbc8edb6499558e1ef 100644 (file)
@@ -22,7 +22,7 @@
 #define X86_FEATURE_TSC                (0*32+ 4) /* Time Stamp Counter */
 #define X86_FEATURE_MSR                (0*32+ 5) /* Model-Specific Registers */
 #define X86_FEATURE_PAE                (0*32+ 6) /* Physical Address Extensions */
-#define X86_FEATURE_MCE                (0*32+ 7) /* Machine Check Architecture */
+#define X86_FEATURE_MCE                (0*32+ 7) /* Machine Check Exception */
 #define X86_FEATURE_CX8                (0*32+ 8) /* CMPXCHG8 instruction */
 #define X86_FEATURE_APIC       (0*32+ 9) /* Onboard APIC */
 #define X86_FEATURE_SEP                (0*32+11) /* SYSENTER/SYSEXIT */
@@ -94,6 +94,7 @@
 #define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */
 #define X86_FEATURE_NONSTOP_TSC        (3*32+24) /* TSC does not stop in C states */
 #define X86_FEATURE_CLFLUSH_MONITOR (3*32+25) /* "" clflush reqd with monitor */
+#define X86_FEATURE_EXTD_APICID        (3*32+26) /* has extended APICID (8 bits) */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
 #define X86_FEATURE_XMM3       (4*32+ 0) /* "pni" SSE-3 */
 #define X86_FEATURE_XMM4_1     (4*32+19) /* "sse4_1" SSE-4.1 */
 #define X86_FEATURE_XMM4_2     (4*32+20) /* "sse4_2" SSE-4.2 */
 #define X86_FEATURE_X2APIC     (4*32+21) /* x2APIC */
+#define X86_FEATURE_MOVBE      (4*32+22) /* MOVBE instruction */
+#define X86_FEATURE_POPCNT      (4*32+23) /* POPCNT instruction */
 #define X86_FEATURE_AES                (4*32+25) /* AES instructions */
 #define X86_FEATURE_XSAVE      (4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */
 #define X86_FEATURE_OSXSAVE    (4*32+27) /* "" XSAVE enabled in the OS */
@@ -192,11 +195,11 @@ extern const char * const x86_power_flags[32];
 #define clear_cpu_cap(c, bit)  clear_bit(bit, (unsigned long *)((c)->x86_capability))
 #define setup_clear_cpu_cap(bit) do { \
        clear_cpu_cap(&boot_cpu_data, bit);     \
-       set_bit(bit, (unsigned long *)cleared_cpu_caps); \
+       set_bit(bit, (unsigned long *)cpu_caps_cleared); \
 } while (0)
 #define setup_force_cpu_cap(bit) do { \
        set_cpu_cap(&boot_cpu_data, bit);       \
-       clear_bit(bit, (unsigned long *)cleared_cpu_caps);      \
+       set_bit(bit, (unsigned long *)cpu_caps_set);    \
 } while (0)
 
 #define cpu_has_fpu            boot_cpu_has(X86_FEATURE_FPU)
index a8f672ba100c541fa893c4167dffabfab1c97561..70dac199b093d6727db43ac652aa92c26e41eb20 100644 (file)
@@ -15,8 +15,8 @@
  * - buffer allocation (memory accounting)
  *
  *
- * Copyright (C) 2007-2008 Intel Corporation.
- * Markus Metzger <markus.t.metzger@intel.com>, 2007-2008
+ * Copyright (C) 2007-2009 Intel Corporation.
+ * Markus Metzger <markus.t.metzger@intel.com>, 2007-2009
  */
 
 #ifndef _ASM_X86_DS_H
@@ -83,8 +83,10 @@ enum ds_feature {
  * The interrupt threshold is independent from the overflow callback
  * to allow users to use their own overflow interrupt handling mechanism.
  *
- * task: the task to request recording for;
- *       NULL for per-cpu recording on the current cpu
+ * The function might sleep.
+ *
+ * task: the task to request recording for
+ * cpu:  the cpu to request recording for
  * base: the base pointer for the (non-pageable) buffer;
  * size: the size of the provided buffer in bytes
  * ovfl: pointer to a function to be called on buffer overflow;
@@ -93,19 +95,28 @@ enum ds_feature {
  *     -1 if no interrupt threshold is requested.
  * flags: a bit-mask of the above flags
  */
-extern struct bts_tracer *ds_request_bts(struct task_struct *task,
-                                        void *base, size_t size,
-                                        bts_ovfl_callback_t ovfl,
-                                        size_t th, unsigned int flags);
-extern struct pebs_tracer *ds_request_pebs(struct task_struct *task,
-                                          void *base, size_t size,
-                                          pebs_ovfl_callback_t ovfl,
-                                          size_t th, unsigned int flags);
+extern struct bts_tracer *ds_request_bts_task(struct task_struct *task,
+                                             void *base, size_t size,
+                                             bts_ovfl_callback_t ovfl,
+                                             size_t th, unsigned int flags);
+extern struct bts_tracer *ds_request_bts_cpu(int cpu, void *base, size_t size,
+                                            bts_ovfl_callback_t ovfl,
+                                            size_t th, unsigned int flags);
+extern struct pebs_tracer *ds_request_pebs_task(struct task_struct *task,
+                                               void *base, size_t size,
+                                               pebs_ovfl_callback_t ovfl,
+                                               size_t th, unsigned int flags);
+extern struct pebs_tracer *ds_request_pebs_cpu(int cpu,
+                                              void *base, size_t size,
+                                              pebs_ovfl_callback_t ovfl,
+                                              size_t th, unsigned int flags);
 
 /*
  * Release BTS or PEBS resources
  * Suspend and resume BTS or PEBS tracing
  *
+ * Must be called with irq's enabled.
+ *
  * tracer: the tracer handle returned from ds_request_~()
  */
 extern void ds_release_bts(struct bts_tracer *tracer);
@@ -115,6 +126,28 @@ extern void ds_release_pebs(struct pebs_tracer *tracer);
 extern void ds_suspend_pebs(struct pebs_tracer *tracer);
 extern void ds_resume_pebs(struct pebs_tracer *tracer);
 
+/*
+ * Release BTS or PEBS resources
+ * Suspend and resume BTS or PEBS tracing
+ *
+ * Cpu tracers must call this on the traced cpu.
+ * Task tracers must call ds_release_~_noirq() for themselves.
+ *
+ * May be called with irq's disabled.
+ *
+ * Returns 0 if successful;
+ * -EPERM if the cpu tracer does not trace the current cpu.
+ * -EPERM if the task tracer does not trace itself.
+ *
+ * tracer: the tracer handle returned from ds_request_~()
+ */
+extern int ds_release_bts_noirq(struct bts_tracer *tracer);
+extern int ds_suspend_bts_noirq(struct bts_tracer *tracer);
+extern int ds_resume_bts_noirq(struct bts_tracer *tracer);
+extern int ds_release_pebs_noirq(struct pebs_tracer *tracer);
+extern int ds_suspend_pebs_noirq(struct pebs_tracer *tracer);
+extern int ds_resume_pebs_noirq(struct pebs_tracer *tracer);
+
 
 /*
  * The raw DS buffer state as it is used for BTS and PEBS recording.
@@ -170,9 +203,9 @@ struct bts_struct {
                } lbr;
                /* BTS_TASK_ARRIVES or BTS_TASK_DEPARTS */
                struct {
-                       __u64 jiffies;
+                       __u64 clock;
                        pid_t pid;
-               } timestamp;
+               } event;
        } variant;
 };
 
@@ -201,8 +234,12 @@ struct bts_trace {
 struct pebs_trace {
        struct ds_trace ds;
 
-       /* the PEBS reset value */
-       unsigned long long reset_value;
+       /* the number of valid counters in the below array */
+       unsigned int counters;
+
+#define MAX_PEBS_COUNTERS 4
+       /* the counter reset value */
+       unsigned long long counter_reset[MAX_PEBS_COUNTERS];
 };
 
 
@@ -237,9 +274,11 @@ extern int ds_reset_pebs(struct pebs_tracer *tracer);
  * Returns 0 on success; -Eerrno on error
  *
  * tracer: the tracer handle returned from ds_request_pebs()
+ * counter: the index of the counter
  * value: the new counter reset value
  */
-extern int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value);
+extern int ds_set_pebs_reset(struct pebs_tracer *tracer,
+                            unsigned int counter, u64 value);
 
 /*
  * Initialization
@@ -252,21 +291,12 @@ extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *);
  */
 extern void ds_switch_to(struct task_struct *prev, struct task_struct *next);
 
-/*
- * Task clone/init and cleanup work
- */
-extern void ds_copy_thread(struct task_struct *tsk, struct task_struct *father);
-extern void ds_exit_thread(struct task_struct *tsk);
-
 #else /* CONFIG_X86_DS */
 
 struct cpuinfo_x86;
 static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {}
 static inline void ds_switch_to(struct task_struct *prev,
                                struct task_struct *next) {}
-static inline void ds_copy_thread(struct task_struct *tsk,
-                                 struct task_struct *father) {}
-static inline void ds_exit_thread(struct task_struct *tsk) {}
 
 #endif /* CONFIG_X86_DS */
 #endif /* _ASM_X86_DS_H */
index b762ea49bd703ab3b28958cf83b6908e825e57a4..3bd1777a4c8b3c2e647659c6c1ad6e8eb4bbbcf0 100644 (file)
@@ -63,7 +63,26 @@ extern unsigned long io_apic_irqs;
 extern void init_VISWS_APIC_irqs(void);
 extern void setup_IO_APIC(void);
 extern void disable_IO_APIC(void);
-extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
+
+struct io_apic_irq_attr {
+       int ioapic;
+       int ioapic_pin;
+       int trigger;
+       int polarity;
+};
+
+static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr,
+                                       int ioapic, int ioapic_pin,
+                                       int trigger, int polarity)
+{
+       irq_attr->ioapic     = ioapic;
+       irq_attr->ioapic_pin = ioapic_pin;
+       irq_attr->trigger    = trigger;
+       irq_attr->polarity   = polarity;
+}
+
+extern int IO_APIC_get_PCI_irq_vector(int bus, int devfn, int pin,
+                                       struct io_apic_irq_attr *irq_attr);
 extern void setup_ioapic_dest(void);
 
 extern void enable_IO_APIC(void);
@@ -78,7 +97,11 @@ extern void eisa_set_level_irq(unsigned int irq);
 /* SMP */
 extern void smp_apic_timer_interrupt(struct pt_regs *);
 extern void smp_spurious_interrupt(struct pt_regs *);
+extern void smp_generic_interrupt(struct pt_regs *);
 extern void smp_error_interrupt(struct pt_regs *);
+#ifdef CONFIG_X86_IO_APIC
+extern asmlinkage void smp_irq_move_cleanup_interrupt(void);
+#endif
 #ifdef CONFIG_SMP
 extern void smp_reschedule_interrupt(struct pt_regs *);
 extern void smp_call_function_interrupt(struct pt_regs *);
index 71c9e51839827dfc14ec28858467c2ea4815297c..175adf58dd4f8e3cec35d69123d4640af2ff37c8 100644 (file)
@@ -67,7 +67,7 @@ static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
                     ".previous\n"
                     _ASM_EXTABLE(1b, 3b)
                     : [err] "=r" (err)
-#if 0 /* See comment in __save_init_fpu() below. */
+#if 0 /* See comment in fxsave() below. */
                     : [fx] "r" (fx), "m" (*fx), "0" (0));
 #else
                     : [fx] "cdaSDb" (fx), "m" (*fx), "0" (0));
@@ -75,14 +75,6 @@ static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
        return err;
 }
 
-static inline int restore_fpu_checking(struct task_struct *tsk)
-{
-       if (task_thread_info(tsk)->status & TS_XSAVE)
-               return xrstor_checking(&tsk->thread.xstate->xsave);
-       else
-               return fxrstor_checking(&tsk->thread.xstate->fxsave);
-}
-
 /* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
    is pending. Clear the x87 state here by setting it to fixed
    values. The kernel data segment can be sometimes 0 and sometimes
@@ -120,7 +112,7 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
                     ".previous\n"
                     _ASM_EXTABLE(1b, 3b)
                     : [err] "=r" (err), "=m" (*fx)
-#if 0 /* See comment in __fxsave_clear() below. */
+#if 0 /* See comment in fxsave() below. */
                     : [fx] "r" (fx), "0" (0));
 #else
                     : [fx] "cdaSDb" (fx), "0" (0));
@@ -185,12 +177,9 @@ static inline void tolerant_fwait(void)
        asm volatile("fnclex ; fwait");
 }
 
-static inline void restore_fpu(struct task_struct *tsk)
+/* perform fxrstor iff the processor has extended states, otherwise frstor */
+static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
 {
-       if (task_thread_info(tsk)->status & TS_XSAVE) {
-               xrstor_checking(&tsk->thread.xstate->xsave);
-               return;
-       }
        /*
         * The "nop" is needed to make the instructions the same
         * length.
@@ -199,7 +188,9 @@ static inline void restore_fpu(struct task_struct *tsk)
                "nop ; frstor %1",
                "fxrstor %1",
                X86_FEATURE_FXSR,
-               "m" (tsk->thread.xstate->fxsave));
+               "m" (*fx));
+
+       return 0;
 }
 
 /* We need a safe address that is cheap to find and that is already
@@ -262,6 +253,14 @@ end:
 
 #endif /* CONFIG_X86_64 */
 
+static inline int restore_fpu_checking(struct task_struct *tsk)
+{
+       if (task_thread_info(tsk)->status & TS_XSAVE)
+               return xrstor_checking(&tsk->thread.xstate->xsave);
+       else
+               return fxrstor_checking(&tsk->thread.xstate->fxsave);
+}
+
 /*
  * Signal frame handlers...
  */
@@ -305,18 +304,18 @@ static inline void kernel_fpu_end(void)
 /*
  * Some instructions like VIA's padlock instructions generate a spurious
  * DNA fault but don't modify SSE registers. And these instructions
- * get used from interrupt context aswell. To prevent these kernel instructions
- * in interrupt context interact wrongly with other user/kernel fpu usage, we
+ * get used from interrupt context as well. To prevent these kernel instructions
+ * in interrupt context interacting wrongly with other user/kernel fpu usage, we
  * should use them only in the context of irq_ts_save/restore()
  */
 static inline int irq_ts_save(void)
 {
        /*
-        * If we are in process context, we are ok to take a spurious DNA fault.
-        * Otherwise, doing clts() in process context require pre-emption to
-        * be disabled or some heavy lifting like kernel_fpu_begin()
+        * If in process context and not atomic, we can take a spurious DNA fault.
+        * Otherwise, doing clts() in process context requires disabling preemption
+        * or some heavy lifting like kernel_fpu_begin()
         */
-       if (!in_interrupt())
+       if (!in_atomic())
                return 0;
 
        if (read_cr0() & X86_CR0_TS) {
index 1a99e6c092afcfaaad1a73b95ee4ecc7249f231b..58d7091eeb1fc1e8955c87246121060fbb851d31 100644 (file)
@@ -60,8 +60,4 @@ extern struct irq_chip i8259A_chip;
 extern void mask_8259A(void);
 extern void unmask_8259A(void);
 
-#ifdef CONFIG_X86_32
-extern void init_ISA_irqs(void);
-#endif
-
 #endif /* _ASM_X86_I8259_H */
index 9d826e436010005254bb04e13bac1ee45d802b75..daf866ed0612413f3781cdf6f863e8038daebe85 100644 (file)
@@ -154,22 +154,19 @@ extern int timer_through_8259;
 extern int io_apic_get_unique_id(int ioapic, int apic_id);
 extern int io_apic_get_version(int ioapic);
 extern int io_apic_get_redir_entries(int ioapic);
-extern int io_apic_set_pci_routing(int ioapic, int pin, int irq,
-                                  int edge_level, int active_high_low);
 #endif /* CONFIG_ACPI */
 
+struct io_apic_irq_attr;
+extern int io_apic_set_pci_routing(struct device *dev, int irq,
+                struct io_apic_irq_attr *irq_attr);
 extern int (*ioapic_renumber_irq)(int ioapic, int irq);
 extern void ioapic_init_mappings(void);
 
-#ifdef CONFIG_X86_64
 extern struct IO_APIC_route_entry **alloc_ioapic_entries(void);
 extern void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries);
 extern int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
 extern void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
 extern int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
-extern void reinit_intr_remapped_IO_APIC(int intr_remapping,
-       struct IO_APIC_route_entry **ioapic_entries);
-#endif
 
 extern void probe_nr_irqs_gsi(void);
 
index 86af26091d6c3c2146da4e5f6f3abbfd6cb165ba..0e9fe1d9d9715db6a2fb952eff4b917465c3d64b 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef _ASM_X86_IOMAP_H
+#define _ASM_X86_IOMAP_H
+
 /*
  * Copyright Â© 2008 Ingo Molnar
  *
@@ -31,3 +34,5 @@ iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
 
 void
 iounmap_atomic(void *kvaddr, enum km_type type);
+
+#endif /* _ASM_X86_IOMAP_H */
index 0396760fccb85be05de0d5666c6019316d386d55..f275e2244505b98308ca72e66e26c250d29c61a8 100644 (file)
@@ -1,6 +1,6 @@
 #ifndef _ASM_X86_IRQ_REMAPPING_H
 #define _ASM_X86_IRQ_REMAPPING_H
 
-#define IRTE_DEST(dest) ((x2apic) ? dest : dest << 8)
+#define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8)
 
 #endif /* _ASM_X86_IRQ_REMAPPING_H */
index 3cbd79bbb47c82613341fca01ee6e174319342fe..910b5a3d6751fea966c71553cbda17bd5469805a 100644 (file)
@@ -34,6 +34,7 @@
 
 #ifdef CONFIG_X86_32
 # define SYSCALL_VECTOR                        0x80
+# define IA32_SYSCALL_VECTOR           0x80
 #else
 # define IA32_SYSCALL_VECTOR           0x80
 #endif
index 54c8cc53b24dd732829da23805c96f64b92fa168..c2d1f3b58e5f1342607280be6a71d434796482dd 100644 (file)
@@ -12,4 +12,17 @@ extern int cache_k8_northbridges(void);
 extern void k8_flush_garts(void);
 extern int k8_scan_nodes(unsigned long start, unsigned long end);
 
+#ifdef CONFIG_K8_NB
+static inline struct pci_dev *node_to_k8_nb_misc(int node)
+{
+       return (node < num_k8_northbridges) ? k8_northbridges[node] : NULL;
+}
+#else
+static inline struct pci_dev *node_to_k8_nb_misc(int node)
+{
+       return NULL;
+}
+#endif
+
+
 #endif /* _ASM_X86_K8_H */
index dc3f6cf117045ee50b2e92aa87a9b772ce8150bd..125be8b19568e2828614d85b741d5ee2e2a53535 100644 (file)
@@ -16,6 +16,7 @@
 #define __KVM_HAVE_MSI
 #define __KVM_HAVE_USER_NMI
 #define __KVM_HAVE_GUEST_DEBUG
+#define __KVM_HAVE_MSIX
 
 /* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
index f0faf58044ff6c6215d1a78739b90a3b9d22336e..eabdc1cfab5c6143874569c5e92eb065d8966ae4 100644 (file)
@@ -185,6 +185,7 @@ union kvm_mmu_page_role {
                unsigned access:3;
                unsigned invalid:1;
                unsigned cr4_pge:1;
+               unsigned nxe:1;
        };
 };
 
@@ -212,7 +213,6 @@ struct kvm_mmu_page {
        int multimapped;         /* More than one parent_pte? */
        int root_count;          /* Currently serving as active root */
        bool unsync;
-       bool global;
        unsigned int unsync_children;
        union {
                u64 *parent_pte;               /* !multimapped */
@@ -261,13 +261,11 @@ struct kvm_mmu {
        union kvm_mmu_page_role base_role;
 
        u64 *pae_root;
+       u64 rsvd_bits_mask[2][4];
 };
 
 struct kvm_vcpu_arch {
        u64 host_tsc;
-       int interrupt_window_open;
-       unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
-       DECLARE_BITMAP(irq_pending, KVM_NR_INTERRUPTS);
        /*
         * rip and regs accesses must go through
         * kvm_{register,rip}_{read,write} functions.
@@ -286,6 +284,7 @@ struct kvm_vcpu_arch {
        u64 shadow_efer;
        u64 apic_base;
        struct kvm_lapic *apic;    /* kernel irqchip context */
+       int32_t apic_arb_prio;
        int mp_state;
        int sipi_vector;
        u64 ia32_misc_enable_msr;
@@ -320,6 +319,8 @@ struct kvm_vcpu_arch {
        struct kvm_pio_request pio;
        void *pio_data;
 
+       u8 event_exit_inst_len;
+
        struct kvm_queued_exception {
                bool pending;
                bool has_error_code;
@@ -329,11 +330,12 @@ struct kvm_vcpu_arch {
 
        struct kvm_queued_interrupt {
                bool pending;
+               bool soft;
                u8 nr;
        } interrupt;
 
        struct {
-               int active;
+               int vm86_active;
                u8 save_iopl;
                struct kvm_save_segment {
                        u16 selector;
@@ -356,9 +358,9 @@ struct kvm_vcpu_arch {
        unsigned int time_offset;
        struct page *time_page;
 
+       bool singlestep; /* guest is single stepped by KVM */
        bool nmi_pending;
        bool nmi_injected;
-       bool nmi_window_open;
 
        struct mtrr_state_type mtrr_state;
        u32 pat;
@@ -392,15 +394,14 @@ struct kvm_arch{
         */
        struct list_head active_mmu_pages;
        struct list_head assigned_dev_head;
-       struct list_head oos_global_pages;
        struct iommu_domain *iommu_domain;
+       int iommu_flags;
        struct kvm_pic *vpic;
        struct kvm_ioapic *vioapic;
        struct kvm_pit *vpit;
        struct hlist_head irq_ack_notifier_list;
        int vapics_in_nmi_mode;
 
-       int round_robin_prev_vcpu;
        unsigned int tss_addr;
        struct page *apic_access_page;
 
@@ -423,7 +424,6 @@ struct kvm_vm_stat {
        u32 mmu_recycled;
        u32 mmu_cache_miss;
        u32 mmu_unsync;
-       u32 mmu_unsync_global;
        u32 remote_tlb_flush;
        u32 lpages;
 };
@@ -443,7 +443,6 @@ struct kvm_vcpu_stat {
        u32 halt_exits;
        u32 halt_wakeup;
        u32 request_irq_exits;
-       u32 request_nmi_exits;
        u32 irq_exits;
        u32 host_state_reload;
        u32 efer_reload;
@@ -511,20 +510,22 @@ struct kvm_x86_ops {
        void (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
        int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
        void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
+       void (*set_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask);
+       u32 (*get_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask);
        void (*patch_hypercall)(struct kvm_vcpu *vcpu,
                                unsigned char *hypercall_addr);
-       int (*get_irq)(struct kvm_vcpu *vcpu);
-       void (*set_irq)(struct kvm_vcpu *vcpu, int vec);
+       void (*set_irq)(struct kvm_vcpu *vcpu);
+       void (*set_nmi)(struct kvm_vcpu *vcpu);
        void (*queue_exception)(struct kvm_vcpu *vcpu, unsigned nr,
                                bool has_error_code, u32 error_code);
-       bool (*exception_injected)(struct kvm_vcpu *vcpu);
-       void (*inject_pending_irq)(struct kvm_vcpu *vcpu);
-       void (*inject_pending_vectors)(struct kvm_vcpu *vcpu,
-                                      struct kvm_run *run);
-
+       int (*interrupt_allowed)(struct kvm_vcpu *vcpu);
+       int (*nmi_allowed)(struct kvm_vcpu *vcpu);
+       void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
+       void (*enable_irq_window)(struct kvm_vcpu *vcpu);
+       void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
        int (*set_tss_addr)(struct kvm *kvm, unsigned int addr);
        int (*get_tdp_level)(void);
-       int (*get_mt_mask_shift)(void);
+       u64 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio);
 };
 
 extern struct kvm_x86_ops *kvm_x86_ops;
@@ -538,7 +539,7 @@ int kvm_mmu_setup(struct kvm_vcpu *vcpu);
 void kvm_mmu_set_nonpresent_ptes(u64 trap_pte, u64 notrap_pte);
 void kvm_mmu_set_base_ptes(u64 base_pte);
 void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask,
-               u64 dirty_mask, u64 nx_mask, u64 x_mask, u64 mt_mask);
+               u64 dirty_mask, u64 nx_mask, u64 x_mask);
 
 int kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
 void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot);
@@ -552,6 +553,7 @@ int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
                          const void *val, int bytes);
 int kvm_pv_mmu_op(struct kvm_vcpu *vcpu, unsigned long bytes,
                  gpa_t addr, unsigned long *ret);
+u8 kvm_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn);
 
 extern bool tdp_enabled;
 
@@ -563,6 +565,7 @@ enum emulation_result {
 
 #define EMULTYPE_NO_DECODE         (1 << 0)
 #define EMULTYPE_TRAP_UD           (1 << 1)
+#define EMULTYPE_SKIP              (1 << 2)
 int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run,
                        unsigned long cr2, u16 error_code, int emulation_type);
 void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context);
@@ -638,7 +641,6 @@ void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
 int kvm_mmu_load(struct kvm_vcpu *vcpu);
 void kvm_mmu_unload(struct kvm_vcpu *vcpu);
 void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu);
-void kvm_mmu_sync_global(struct kvm_vcpu *vcpu);
 
 int kvm_emulate_hypercall(struct kvm_vcpu *vcpu);
 
@@ -769,6 +771,8 @@ enum {
 #define HF_GIF_MASK            (1 << 0)
 #define HF_HIF_MASK            (1 << 1)
 #define HF_VINTR_MASK          (1 << 2)
+#define HF_NMI_MASK            (1 << 3)
+#define HF_IRET_MASK           (1 << 4)
 
 /*
  * Hardware virtualization extension instructions may fault if a
@@ -791,5 +795,6 @@ asmlinkage void kvm_handle_fault_on_reboot(void);
 #define KVM_ARCH_WANT_MMU_NOTIFIER
 int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
 int kvm_age_hva(struct kvm *kvm, unsigned long hva);
+int cpuid_maxphyaddr(struct kvm_vcpu *vcpu);
 
 #endif /* _ASM_X86_KVM_HOST_H */
index 6a159732881a6b4067fd552fd4576cce797a5926..b7ed2c423116be32942ef23b63e5dc4f09492d9d 100644 (file)
@@ -143,6 +143,9 @@ struct decode_cache {
        struct fetch_cache fetch;
 };
 
+#define X86_SHADOW_INT_MOV_SS  1
+#define X86_SHADOW_INT_STI     2
+
 struct x86_emulate_ctxt {
        /* Register state before/after emulation. */
        struct kvm_vcpu *vcpu;
@@ -152,6 +155,9 @@ struct x86_emulate_ctxt {
        int mode;
        u32 cs_base;
 
+       /* interruptibility state, as a result of execution of STI or MOV SS */
+       int interruptibility;
+
        /* decode cache */
        struct decode_cache decode;
 };
index c882664716c1d13e5678aa188fb0ccf75d50acca..ef51b501e22a6e53bf4ae7e2d9e2566760f72ee1 100644 (file)
@@ -9,20 +9,31 @@ struct cpu_signature {
 
 struct device;
 
+enum ucode_state { UCODE_ERROR, UCODE_OK, UCODE_NFOUND };
+
 struct microcode_ops {
-       int  (*request_microcode_user) (int cpu, const void __user *buf, size_t size);
-       int  (*request_microcode_fw) (int cpu, struct device *device);
+       enum ucode_state (*request_microcode_user) (int cpu,
+                               const void __user *buf, size_t size);
 
-       void (*apply_microcode) (int cpu);
+       enum ucode_state (*request_microcode_fw) (int cpu,
+                               struct device *device);
 
-       int  (*collect_cpu_info) (int cpu, struct cpu_signature *csig);
        void (*microcode_fini_cpu) (int cpu);
+
+       /*
+        * The generic 'microcode_core' part guarantees that
+        * the callbacks below run on a target cpu when they
+        * are being called.
+        * See also the "Synchronization" section in microcode_core.c.
+        */
+       int (*apply_microcode) (int cpu);
+       int (*collect_cpu_info) (int cpu, struct cpu_signature *csig);
 };
 
 struct ucode_cpu_info {
-       struct cpu_signature cpu_sig;
-       int valid;
-       void *mc;
+       struct cpu_signature    cpu_sig;
+       int                     valid;
+       void                    *mc;
 };
 extern struct ucode_cpu_info ucode_cpu_info[];
 
index 642fc7fc8cdc3fe8aedea4ddb60cacabc7925983..e2a1bb6d71ea832f6a6dbb3fc9ad7b58c7c9e6c4 100644 (file)
@@ -61,9 +61,11 @@ extern void get_smp_config(void);
 #ifdef CONFIG_X86_MPPARSE
 extern void find_smp_config(void);
 extern void early_reserve_e820_mpc_new(void);
+extern int enable_update_mptable;
 #else
 static inline void find_smp_config(void) { }
 static inline void early_reserve_e820_mpc_new(void) { }
+#define enable_update_mptable 0
 #endif
 
 void __cpuinit generic_processor_info(int apicid, int version);
@@ -72,20 +74,13 @@ extern void mp_register_ioapic(int id, u32 address, u32 gsi_base);
 extern void mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger,
                                   u32 gsi);
 extern void mp_config_acpi_legacy_irqs(void);
-extern int mp_register_gsi(u32 gsi, int edge_level, int active_high_low);
+struct device;
+extern int mp_register_gsi(struct device *dev, u32 gsi, int edge_level,
+                                int active_high_low);
 extern int acpi_probe_gsi(void);
 #ifdef CONFIG_X86_IO_APIC
-extern int mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin,
-                               u32 gsi, int triggering, int polarity);
 extern int mp_find_ioapic(int gsi);
 extern int mp_find_ioapic_pin(int ioapic, int gsi);
-#else
-static inline int
-mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin,
-                  u32 gsi, int triggering, int polarity)
-{
-       return 0;
-}
 #endif
 #else /* !CONFIG_ACPI: */
 static inline int acpi_probe_gsi(void)
index ec41fc16c167cb19ef617f9a5e7ec2dda6f88bd1..4d58d04fca830bc56ab8bf62009661ad77a85f3e 100644 (file)
 #define MSR_K8_TOP_MEM1                        0xc001001a
 #define MSR_K8_TOP_MEM2                        0xc001001d
 #define MSR_K8_SYSCFG                  0xc0010010
-#define MSR_K8_HWCR                    0xc0010015
 #define MSR_K8_INT_PENDING_MSG         0xc0010055
 /* C1E active bits in int pending message */
 #define K8_INTP_C1E_ACTIVE_MASK                0x18000000
index 638bf6241807a9ab9c36def7541c690ccb230e07..22603764e7db35c6098cf5d58befe070fb496a4a 100644 (file)
 
 #include <asm/asm.h>
 #include <asm/errno.h>
+#include <asm/cpumask.h>
+
+struct msr {
+       union {
+               struct {
+                       u32 l;
+                       u32 h;
+               };
+               u64 q;
+       };
+};
 
 static inline unsigned long long native_read_tscp(unsigned int *aux)
 {
@@ -216,6 +227,8 @@ do {                                                            \
 #ifdef CONFIG_SMP
 int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
+void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs);
+void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs);
 int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
 #else  /*  CONFIG_SMP  */
@@ -229,6 +242,16 @@ static inline int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
        wrmsr(msr_no, l, h);
        return 0;
 }
+static inline void rdmsr_on_cpus(const cpumask_t *m, u32 msr_no,
+                               struct msr *msrs)
+{
+       rdmsr_on_cpu(0, msr_no, &(msrs[0].l), &(msrs[0].h));
+}
+static inline void wrmsr_on_cpus(const cpumask_t *m, u32 msr_no,
+                               struct msr *msrs)
+{
+       wrmsr_on_cpu(0, msr_no, msrs[0].l, msrs[0].h);
+}
 static inline int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no,
                                    u32 *l, u32 *h)
 {
index c45a0a568dff092227b1436a48e7dab5434dc4fa..c97264409934be915d24d35395c1c0af5956aa7b 100644 (file)
@@ -64,7 +64,7 @@ static inline int nmi_watchdog_active(void)
         * but since they are power of two we could use a
         * cheaper way --cvg
         */
-       return nmi_watchdog & 0x3;
+       return nmi_watchdog & (NMI_LOCAL_APIC | NMI_IO_APIC);
 }
 #endif
 
index 064ed6df4cbec292758631a4a5a36aa3b77260c0..c4ae822e415f907093eabd2531d97506a891b691 100644 (file)
@@ -17,9 +17,6 @@ extern int compute_hash_shift(struct bootnode *nodes, int numblks,
 extern void numa_init_array(void);
 extern int numa_off;
 
-extern void srat_reserve_add_area(int nodeid);
-extern int hotadd_percent;
-
 extern s16 apicid_to_node[MAX_LOCAL_APIC];
 
 extern unsigned long numa_free_all_bootmem(void);
@@ -27,6 +24,13 @@ extern void setup_node_bootmem(int nodeid, unsigned long start,
                               unsigned long end);
 
 #ifdef CONFIG_NUMA
+/*
+ * Too small node sizes may confuse the VM badly. Usually they
+ * result from BIOS bugs. So dont recognize nodes as standalone
+ * NUMA entities that have less than this amount of RAM listed:
+ */
+#define NODE_MIN_SIZE (4*1024*1024)
+
 extern void __init init_cpu_to_node(void);
 extern void __cpuinit numa_set_node(int cpu, int node);
 extern void __cpuinit numa_clear_node(int cpu);
index 0f915ae649a717e99ebdfc079652b25fda315e72..6f1b7331313f1af2744c50accfecd26e069a5bed 100644 (file)
@@ -54,10 +54,6 @@ extern unsigned int __VMALLOC_RESERVE;
 extern int sysctl_legacy_va_layout;
 
 extern void find_low_pfn_range(void);
-extern unsigned long init_memory_mapping(unsigned long start,
-                                        unsigned long end);
-extern void initmem_init(unsigned long, unsigned long);
-extern void free_initmem(void);
 extern void setup_bootmem_allocator(void);
 
 #endif /* !__ASSEMBLY__ */
index d38c91b7024834a56be59db9c9b1bf411c698c50..8d382d3abf38cf9ec0be9c6164589d431017fc41 100644 (file)
  */
 #define __PAGE_OFFSET           _AC(0xffff880000000000, UL)
 
-#define __PHYSICAL_START       CONFIG_PHYSICAL_START
-#define __KERNEL_ALIGN         0x200000
-
-/*
- * Make sure kernel is aligned to 2MB address. Catching it at compile
- * time is better. Change your config file and compile the kernel
- * for a 2MB aligned address (CONFIG_PHYSICAL_START)
- */
-#if (CONFIG_PHYSICAL_START % __KERNEL_ALIGN) != 0
-#error "CONFIG_PHYSICAL_START must be a multiple of 2MB"
-#endif
+#define __PHYSICAL_START       ((CONFIG_PHYSICAL_START +               \
+                                 (CONFIG_PHYSICAL_ALIGN - 1)) &        \
+                                ~(CONFIG_PHYSICAL_ALIGN - 1))
 
 #define __START_KERNEL         (__START_KERNEL_map + __PHYSICAL_START)
 #define __START_KERNEL_map     _AC(0xffffffff80000000, UL)
 
-/* See Documentation/x86_64/mm.txt for a description of the memory map. */
+/* See Documentation/x86/x86_64/mm.txt for a description of the memory map. */
 #define __PHYSICAL_MASK_SHIFT  46
 #define __VIRTUAL_MASK_SHIFT   48
 
@@ -71,12 +63,6 @@ extern unsigned long __phys_addr(unsigned long);
 
 #define vmemmap ((struct page *)VMEMMAP_START)
 
-extern unsigned long init_memory_mapping(unsigned long start,
-                                        unsigned long end);
-
-extern void initmem_init(unsigned long start_pfn, unsigned long end_pfn);
-extern void free_initmem(void);
-
 extern void init_extra_mapping_uc(unsigned long phys, unsigned long size);
 extern void init_extra_mapping_wb(unsigned long phys, unsigned long size);
 
index 826ad37006ab1a075993ddbe69bd3281412b7f09..6473f5ccff859baf2c897ba073f629d14ba6d0ee 100644 (file)
@@ -46,6 +46,12 @@ extern int devmem_is_allowed(unsigned long pagenr);
 extern unsigned long max_low_pfn_mapped;
 extern unsigned long max_pfn_mapped;
 
+extern unsigned long init_memory_mapping(unsigned long start,
+                                        unsigned long end);
+
+extern void initmem_init(unsigned long start_pfn, unsigned long end_pfn);
+extern void free_initmem(void);
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_X86_PAGE_DEFS_H */
index a53da004e08ed8903dbf135fead7e3e09664089a..4fb37c8a0832da8cf51f7a2c771c54fa97af2708 100644 (file)
@@ -56,6 +56,7 @@ struct desc_ptr;
 struct tss_struct;
 struct mm_struct;
 struct desc_struct;
+struct task_struct;
 
 /*
  * Wrapper type for pointers to code which uses the non-standard
@@ -203,7 +204,8 @@ struct pv_cpu_ops {
 
        void (*swapgs)(void);
 
-       struct pv_lazy_ops lazy_mode;
+       void (*start_context_switch)(struct task_struct *prev);
+       void (*end_context_switch)(struct task_struct *next);
 };
 
 struct pv_irq_ops {
@@ -1399,25 +1401,23 @@ enum paravirt_lazy_mode {
 };
 
 enum paravirt_lazy_mode paravirt_get_lazy_mode(void);
-void paravirt_enter_lazy_cpu(void);
-void paravirt_leave_lazy_cpu(void);
+void paravirt_start_context_switch(struct task_struct *prev);
+void paravirt_end_context_switch(struct task_struct *next);
+
 void paravirt_enter_lazy_mmu(void);
 void paravirt_leave_lazy_mmu(void);
-void paravirt_leave_lazy(enum paravirt_lazy_mode mode);
 
-#define  __HAVE_ARCH_ENTER_LAZY_CPU_MODE
-static inline void arch_enter_lazy_cpu_mode(void)
+#define  __HAVE_ARCH_START_CONTEXT_SWITCH
+static inline void arch_start_context_switch(struct task_struct *prev)
 {
-       PVOP_VCALL0(pv_cpu_ops.lazy_mode.enter);
+       PVOP_VCALL1(pv_cpu_ops.start_context_switch, prev);
 }
 
-static inline void arch_leave_lazy_cpu_mode(void)
+static inline void arch_end_context_switch(struct task_struct *next)
 {
-       PVOP_VCALL0(pv_cpu_ops.lazy_mode.leave);
+       PVOP_VCALL1(pv_cpu_ops.end_context_switch, next);
 }
 
-void arch_flush_lazy_cpu_mode(void);
-
 #define  __HAVE_ARCH_ENTER_LAZY_MMU_MODE
 static inline void arch_enter_lazy_mmu_mode(void)
 {
index 29d96d168bc097195e9cbe66ab723c90929e1116..18ef7ebf2631709dad4f26a681fdbf5dff5a8b2b 100644 (file)
@@ -81,6 +81,8 @@ static inline void __init paravirt_pagetable_setup_done(pgd_t *base)
 #define pte_val(x)     native_pte_val(x)
 #define __pte(x)       native_make_pte(x)
 
+#define arch_end_context_switch(prev)  do {} while(0)
+
 #endif /* CONFIG_PARAVIRT */
 
 /*
@@ -503,6 +505,8 @@ static inline int pgd_none(pgd_t pgd)
 
 #ifndef __ASSEMBLY__
 
+extern int direct_gbpages;
+
 /* local pte updates need not use xchg for locking */
 static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
 {
index 6b87bc6d50189263691c10819618bc97deb8c086..abde308fdb0f54e07587e599998c31c4cc45dc66 100644 (file)
@@ -25,10 +25,6 @@ extern pgd_t init_level4_pgt[];
 
 extern void paging_init(void);
 
-#endif /* !__ASSEMBLY__ */
-
-#ifndef __ASSEMBLY__
-
 #define pte_ERROR(e)                                   \
        printk("%s:%d: bad pte %p(%016lx).\n",          \
               __FILE__, __LINE__, &(e), pte_val(e))
@@ -135,8 +131,6 @@ static inline int pgd_large(pgd_t pgd) { return 0; }
 
 #define update_mmu_cache(vma, address, pte) do { } while (0)
 
-extern int direct_gbpages;
-
 /* Encode and de-code a swap entry */
 #if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE
 #define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1)
index fbf42b8e03833d0537b5e8594a4a3f06a154e180..766ea16fbbbda730a9952a67d85c8cda954f62ef 100644 (file)
@@ -51,11 +51,11 @@ typedef struct { pteval_t pte; } pte_t;
 #define PGDIR_SIZE     (_AC(1, UL) << PGDIR_SHIFT)
 #define PGDIR_MASK     (~(PGDIR_SIZE - 1))
 
-
+/* See Documentation/x86/x86_64/mm.txt for a description of the memory map. */
 #define MAXMEM          _AC(__AC(1, UL) << MAX_PHYSMEM_BITS, UL)
-#define VMALLOC_START    _AC(0xffffc20000000000, UL)
-#define VMALLOC_END      _AC(0xffffe1ffffffffff, UL)
-#define VMEMMAP_START   _AC(0xffffe20000000000, UL)
+#define VMALLOC_START    _AC(0xffffc90000000000, UL)
+#define VMALLOC_END      _AC(0xffffe8ffffffffff, UL)
+#define VMEMMAP_START   _AC(0xffffea0000000000, UL)
 #define MODULES_VADDR    _AC(0xffffffffa0000000, UL)
 #define MODULES_END      _AC(0xffffffffff000000, UL)
 #define MODULES_LEN   (MODULES_END - MODULES_VADDR)
index b8238dc8786d9f6b4291c2d7f912abbc0ea04e18..4d258ad76a0fc04925ac484c1fa9b0bfc47a1cb9 100644 (file)
@@ -273,7 +273,6 @@ typedef struct page *pgtable_t;
 
 extern pteval_t __supported_pte_mask;
 extern int nx_enabled;
-extern void set_nx(void);
 
 #define pgprot_writecombine    pgprot_writecombine
 extern pgprot_t pgprot_writecombine(pgprot_t prot);
index c2cceae709c8655338894c15b84c361e65caf727..c7768269b1cf1364b76c948d886deee10de2cf70 100644 (file)
@@ -135,7 +135,8 @@ extern struct cpuinfo_x86   boot_cpu_data;
 extern struct cpuinfo_x86      new_cpu_data;
 
 extern struct tss_struct       doublefault_tss;
-extern __u32                   cleared_cpu_caps[NCAPINTS];
+extern __u32                   cpu_caps_cleared[NCAPINTS];
+extern __u32                   cpu_caps_set[NCAPINTS];
 
 #ifdef CONFIG_SMP
 DECLARE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);
@@ -409,9 +410,6 @@ DECLARE_PER_CPU(unsigned long, stack_canary);
 extern unsigned int xstate_size;
 extern void free_thread_xstate(struct task_struct *);
 extern struct kmem_cache *task_xstate_cachep;
-extern void init_scattered_cpuid_features(struct cpuinfo_x86 *c);
-extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
-extern unsigned short num_cache_leaves;
 
 struct thread_struct {
        /* Cached TLS descriptors: */
@@ -427,8 +425,12 @@ struct thread_struct {
        unsigned short          fsindex;
        unsigned short          gsindex;
 #endif
+#ifdef CONFIG_X86_32
        unsigned long           ip;
+#endif
+#ifdef CONFIG_X86_64
        unsigned long           fs;
+#endif
        unsigned long           gs;
        /* Hardware debugging registers: */
        unsigned long           debugreg0;
@@ -460,14 +462,8 @@ struct thread_struct {
        unsigned                io_bitmap_max;
 /* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set.  */
        unsigned long   debugctlmsr;
-#ifdef CONFIG_X86_DS
-/* Debug Store context; see include/asm-x86/ds.h; goes into MSR_IA32_DS_AREA */
+       /* Debug Store context; see asm/ds.h */
        struct ds_context       *ds_ctx;
-#endif /* CONFIG_X86_DS */
-#ifdef CONFIG_X86_PTRACE_BTS
-/* the signal to send on a bts buffer overflow */
-       unsigned int    bts_ovfl_signal;
-#endif /* CONFIG_X86_PTRACE_BTS */
 };
 
 static inline unsigned long native_get_debugreg(int regno)
@@ -795,6 +791,21 @@ static inline unsigned long get_debugctlmsr(void)
     return debugctlmsr;
 }
 
+static inline unsigned long get_debugctlmsr_on_cpu(int cpu)
+{
+       u64 debugctlmsr = 0;
+       u32 val1, val2;
+
+#ifndef CONFIG_X86_DEBUGCTLMSR
+       if (boot_cpu_data.x86 < 6)
+               return 0;
+#endif
+       rdmsr_on_cpu(cpu, MSR_IA32_DEBUGCTLMSR, &val1, &val2);
+       debugctlmsr = val1 | ((u64)val2 << 32);
+
+       return debugctlmsr;
+}
+
 static inline void update_debugctlmsr(unsigned long debugctlmsr)
 {
 #ifndef CONFIG_X86_DEBUGCTLMSR
@@ -804,6 +815,18 @@ static inline void update_debugctlmsr(unsigned long debugctlmsr)
        wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
 }
 
+static inline void update_debugctlmsr_on_cpu(int cpu,
+                                            unsigned long debugctlmsr)
+{
+#ifndef CONFIG_X86_DEBUGCTLMSR
+       if (boot_cpu_data.x86 < 6)
+               return;
+#endif
+       wrmsr_on_cpu(cpu, MSR_IA32_DEBUGCTLMSR,
+                    (u32)((u64)debugctlmsr),
+                    (u32)((u64)debugctlmsr >> 32));
+}
+
 /*
  * from system description table in BIOS. Mostly for MCA use, but
  * others may find it useful:
@@ -814,6 +837,7 @@ extern unsigned int         BIOS_revision;
 
 /* Boot loader type from the setup header: */
 extern int                     bootloader_type;
+extern int                     bootloader_version;
 
 extern char                    ignore_fpu_irq;
 
@@ -874,7 +898,6 @@ static inline void spin_lock_prefetch(const void *x)
        .vm86_info              = NULL,                                   \
        .sysenter_cs            = __KERNEL_CS,                            \
        .io_bitmap_ptr          = NULL,                                   \
-       .fs                     = __KERNEL_PERCPU,                        \
 }
 
 /*
index 624f133943ed71293aaba1477b9ca20ad0836da8..0f0d908349aa3f375e87f68802cbcb2e7753f725 100644 (file)
@@ -236,12 +236,11 @@ extern int do_get_thread_area(struct task_struct *p, int idx,
 extern int do_set_thread_area(struct task_struct *p, int idx,
                              struct user_desc __user *info, int can_allocate);
 
-extern void x86_ptrace_untrace(struct task_struct *);
-extern void x86_ptrace_fork(struct task_struct *child,
-                           unsigned long clone_flags);
+#ifdef CONFIG_X86_PTRACE_BTS
+extern void ptrace_bts_untrace(struct task_struct *tsk);
 
-#define arch_ptrace_untrace(tsk) x86_ptrace_untrace(tsk)
-#define arch_ptrace_fork(child, flags) x86_ptrace_fork(child, flags)
+#define arch_ptrace_untrace(tsk)       ptrace_bts_untrace(tsk)
+#endif /* CONFIG_X86_PTRACE_BTS */
 
 #endif /* __KERNEL__ */
 
index a4737dddfd5878da05d20fb819592fc58a117a47..64cf2d24fad1c2605c16b528cc10e8e37c9bc77c 100644 (file)
 #endif
 
 #ifdef CONFIG_X86_64
+#ifdef CONFIG_PARAVIRT
+/* Paravirtualized systems may not have PSE or PGE available */
 #define NEED_PSE       0
-#define NEED_MSR       (1<<(X86_FEATURE_MSR & 31))
 #define NEED_PGE       0
+#else
+#define NEED_PSE       (1<<(X86_FEATURE_PSE) & 31)
+#define NEED_PGE       (1<<(X86_FEATURE_PGE) & 31)
+#endif
+#define NEED_MSR       (1<<(X86_FEATURE_MSR & 31))
 #define NEED_FXSR      (1<<(X86_FEATURE_FXSR & 31))
 #define NEED_XMM       (1<<(X86_FEATURE_XMM & 31))
 #define NEED_XMM2      (1<<(X86_FEATURE_XMM2 & 31))
index bdc2ada05ae06056ad95e79bd8d6434d73510f5a..4093d1ed6db2a0b3eebc2983337a1592b673d5bc 100644 (file)
@@ -33,7 +33,6 @@ struct x86_quirks {
        int (*setup_ioapic_ids)(void);
 };
 
-extern void x86_quirk_pre_intr_init(void);
 extern void x86_quirk_intr_init(void);
 
 extern void x86_quirk_trap_init(void);
index 19e0d88b966d7b9154f46d9426450765dcf3d389..6a84ed166aec136334a644cc4fbaa676368ae983 100644 (file)
@@ -180,7 +180,7 @@ extern int safe_smp_processor_id(void);
 static inline int logical_smp_processor_id(void)
 {
        /* we don't want to mark this access volatile - bad code generation */
-       return GET_APIC_LOGICAL_ID(*(u32 *)(APIC_BASE + APIC_LDR));
+       return GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
 }
 
 #endif
index e3cc3c063ec5e77683c088fd80906de90fbf9bd2..4517d6b93188aa55a775be95561b9f4bee045d42 100644 (file)
@@ -27,7 +27,7 @@
 #else /* CONFIG_X86_32 */
 # define SECTION_SIZE_BITS     27 /* matt - 128 is convenient right now */
 # define MAX_PHYSADDR_BITS     44
-# define MAX_PHYSMEM_BITS      44 /* Can be max 45 bits */
+# define MAX_PHYSMEM_BITS      46
 #endif
 
 #endif /* CONFIG_SPARSEMEM */
index 82ada75f3ebf142678325968ea6fa0952308e9a0..85574b7c1bc13c371c4c5bdc8d17146897f95645 100644 (file)
@@ -225,6 +225,7 @@ struct __attribute__ ((__packed__)) vmcb {
 #define SVM_EVTINJ_VALID_ERR (1 << 11)
 
 #define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK
+#define SVM_EXITINTINFO_TYPE_MASK SVM_EVTINJ_TYPE_MASK
 
 #define        SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR
 #define        SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI
index 7043408f6904a9f2d94c817b3488f80fbb4976df..372b76edd63f69053c76bcf7501eb71c35bb8f93 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * syscalls.h - Linux syscall interfaces (arch-specific)
  *
- * Copyright (c) 2008 Jaswinder Singh
+ * Copyright (c) 2008 Jaswinder Singh Rajput
  *
  * This file is released under the GPLv2.
  * See the file COPYING for more details.
 
 #include <linux/compiler.h>
 #include <linux/linkage.h>
-#include <linux/types.h>
 #include <linux/signal.h>
+#include <linux/types.h>
 
 /* Common in X86_32 and X86_64 */
 /* kernel/ioport.c */
 asmlinkage long sys_ioperm(unsigned long, unsigned long, int);
 
+/* kernel/process.c */
+int sys_fork(struct pt_regs *);
+int sys_vfork(struct pt_regs *);
+
 /* kernel/ldt.c */
 asmlinkage int sys_modify_ldt(int, void __user *, unsigned long);
 
+/* kernel/signal.c */
+long sys_rt_sigreturn(struct pt_regs *);
+
 /* kernel/tls.c */
 asmlinkage int sys_set_thread_area(struct user_desc __user *);
 asmlinkage int sys_get_thread_area(struct user_desc __user *);
 
 /* X86_32 only */
 #ifdef CONFIG_X86_32
+/* kernel/ioport.c */
+long sys_iopl(struct pt_regs *);
+
 /* kernel/process_32.c */
-int sys_fork(struct pt_regs *);
 int sys_clone(struct pt_regs *);
-int sys_vfork(struct pt_regs *);
 int sys_execve(struct pt_regs *);
 
-/* kernel/signal_32.c */
+/* kernel/signal.c */
 asmlinkage int sys_sigsuspend(int, int, old_sigset_t);
 asmlinkage int sys_sigaction(int, const struct old_sigaction __user *,
                             struct old_sigaction __user *);
 int sys_sigaltstack(struct pt_regs *);
 unsigned long sys_sigreturn(struct pt_regs *);
-long sys_rt_sigreturn(struct pt_regs *);
-
-/* kernel/ioport.c */
-long sys_iopl(struct pt_regs *);
 
 /* kernel/sys_i386_32.c */
+struct mmap_arg_struct;
+struct sel_arg_struct;
+struct oldold_utsname;
+struct old_utsname;
+
 asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long,
                          unsigned long, unsigned long, unsigned long);
-struct mmap_arg_struct;
 asmlinkage int old_mmap(struct mmap_arg_struct __user *);
-struct sel_arg_struct;
 asmlinkage int old_select(struct sel_arg_struct __user *);
 asmlinkage int sys_ipc(uint, int, int, int, void __user *, long);
-struct old_utsname;
 asmlinkage int sys_uname(struct old_utsname __user *);
-struct oldold_utsname;
 asmlinkage int sys_olduname(struct oldold_utsname __user *);
 
 /* kernel/vm86_32.c */
@@ -65,29 +70,27 @@ int sys_vm86(struct pt_regs *);
 #else /* CONFIG_X86_32 */
 
 /* X86_64 only */
+/* kernel/ioport.c */
+asmlinkage long sys_iopl(unsigned int, struct pt_regs *);
+
 /* kernel/process_64.c */
-asmlinkage long sys_fork(struct pt_regs *);
 asmlinkage long sys_clone(unsigned long, unsigned long,
                          void __user *, void __user *,
                          struct pt_regs *);
-asmlinkage long sys_vfork(struct pt_regs *);
 asmlinkage long sys_execve(char __user *, char __user * __user *,
                           char __user * __user *,
                           struct pt_regs *);
 long sys_arch_prctl(int, unsigned long);
 
-/* kernel/ioport.c */
-asmlinkage long sys_iopl(unsigned int, struct pt_regs *);
-
-/* kernel/signal_64.c */
+/* kernel/signal.c */
 asmlinkage long sys_sigaltstack(const stack_t __user *, stack_t __user *,
                                struct pt_regs *);
-long sys_rt_sigreturn(struct pt_regs *);
 
 /* kernel/sys_x86_64.c */
+struct new_utsname;
+
 asmlinkage long sys_mmap(unsigned long, unsigned long, unsigned long,
                         unsigned long, unsigned long, unsigned long);
-struct new_utsname;
 asmlinkage long sys_uname(struct new_utsname __user *);
 
 #endif /* CONFIG_X86_32 */
index f72956331c49349623014bffc4c241f01c361eee..c4ee8056bacaf9534c1fead0e7cee6b3e578a57b 100644 (file)
@@ -67,6 +67,7 @@ static inline int user_termio_to_kernel_termios(struct ktermios *termios,
        SET_LOW_TERMIOS_BITS(termios, termio, c_oflag);
        SET_LOW_TERMIOS_BITS(termios, termio, c_cflag);
        SET_LOW_TERMIOS_BITS(termios, termio, c_lflag);
+       get_user(termios->c_line, &termio->c_line);
        return copy_from_user(termios->c_cc, termio->c_cc, NCC);
 }
 
index 8820a73ae090aae29aa3454d6f3241ffcbef5440..602c769fc98ca7340f5388fe21e57ce5431b376e 100644 (file)
@@ -94,7 +94,8 @@ struct thread_info {
 #define TIF_FORCED_TF          24      /* true if TF in eflags artificially */
 #define TIF_DEBUGCTLMSR                25      /* uses thread_struct.debugctlmsr */
 #define TIF_DS_AREA_MSR                26      /* uses thread_struct.ds_area_msr */
-#define TIF_SYSCALL_FTRACE     27      /* for ftrace syscall instrumentation */
+#define TIF_LAZY_MMU_UPDATES   27      /* task is updating the mmu lazily */
+#define TIF_SYSCALL_FTRACE     28      /* for ftrace syscall instrumentation */
 
 #define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
@@ -116,6 +117,7 @@ struct thread_info {
 #define _TIF_FORCED_TF         (1 << TIF_FORCED_TF)
 #define _TIF_DEBUGCTLMSR       (1 << TIF_DEBUGCTLMSR)
 #define _TIF_DS_AREA_MSR       (1 << TIF_DS_AREA_MSR)
+#define _TIF_LAZY_MMU_UPDATES  (1 << TIF_LAZY_MMU_UPDATES)
 #define _TIF_SYSCALL_FTRACE    (1 << TIF_SYSCALL_FTRACE)
 
 /* work to do in syscall_trace_enter() */
index 16a5c84b032997f264f704ac68537dc65ba1dbe6..a5ecc9c33e920eda5e50bcfe0313b333b1b2cd31 100644 (file)
@@ -17,7 +17,7 @@
 
 static inline void __native_flush_tlb(void)
 {
-       write_cr3(read_cr3());
+       native_write_cr3(native_read_cr3());
 }
 
 static inline void __native_flush_tlb_global(void)
@@ -32,11 +32,11 @@ static inline void __native_flush_tlb_global(void)
         */
        raw_local_irq_save(flags);
 
-       cr4 = read_cr4();
+       cr4 = native_read_cr4();
        /* clear PGE */
-       write_cr4(cr4 & ~X86_CR4_PGE);
+       native_write_cr4(cr4 & ~X86_CR4_PGE);
        /* write old PGE again and flush TLBs */
-       write_cr4(cr4);
+       native_write_cr4(cr4);
 
        raw_local_irq_restore(flags);
 }
index f44b49abca49b93c1f9386f65e0b2b5df118a354..066ef590d7e054b7ac7c55c99d235a0b4bb73896 100644 (file)
@@ -203,7 +203,8 @@ struct pci_bus;
 void x86_pci_root_bus_res_quirks(struct pci_bus *b);
 
 #ifdef CONFIG_SMP
-#define mc_capable()   (cpumask_weight(cpu_core_mask(0)) != nr_cpu_ids)
+#define mc_capable()   ((boot_cpu_data.x86_max_cores > 1) && \
+                       (cpumask_weight(cpu_core_mask(0)) != nr_cpu_ids))
 #define smt_capable()                  (smp_num_siblings > 1)
 #endif
 
index 0d5342515b8696970ec533572055df8b98ef74a9..bfd74c032fcaa33b7c50b066fbc5f9333ca6387d 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_X86_TRAPS_H
 
 #include <asm/debugreg.h>
+#include <asm/siginfo.h>                       /* TRAP_TRACE, ... */
 
 #ifdef CONFIG_X86_32
 #define dotraplinkage
@@ -13,6 +14,9 @@ asmlinkage void divide_error(void);
 asmlinkage void debug(void);
 asmlinkage void nmi(void);
 asmlinkage void int3(void);
+asmlinkage void xen_debug(void);
+asmlinkage void xen_int3(void);
+asmlinkage void xen_stack_segment(void);
 asmlinkage void overflow(void);
 asmlinkage void bounds(void);
 asmlinkage void invalid_op(void);
@@ -74,7 +78,6 @@ static inline int get_si_code(unsigned long condition)
 }
 
 extern int panic_on_unrecovered_nmi;
-extern int kstack_depth_to_print;
 
 void math_error(void __user *);
 void math_emulate(struct math_emu_info *);
index 6e72d74cf8dc74b7720f5cb79ba355a926e7fa6e..708dae61262df4926eaef9d7b4c2aa5a049c0e74 100644 (file)
 #define __NR_inotify_init1     332
 #define __NR_preadv            333
 #define __NR_pwritev           334
+#define __NR_rt_tgsigqueueinfo 335
 
 #ifdef __KERNEL__
 
index f81829462325f6328a6e6d9c3667da02e9f616d0..4e2b054044000be53a86c2123170969f2851141e 100644 (file)
@@ -657,6 +657,8 @@ __SYSCALL(__NR_inotify_init1, sys_inotify_init1)
 __SYSCALL(__NR_preadv, sys_preadv)
 #define __NR_pwritev                           296
 __SYSCALL(__NR_pwritev, sys_pwritev)
+#define __NR_rt_tgsigqueueinfo                 297
+__SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo)
 
 
 #ifndef __NO_STUBS
index 9b0e61bf7a88dc2a68521384ea68950cd900478e..bddd44f2f0ab5b3dc7dc0e8ad19fe6df52a0525a 100644 (file)
@@ -37,7 +37,7 @@
 #define UV_CPUS_PER_ACT_STATUS         32
 #define UV_ACT_STATUS_MASK             0x3
 #define UV_ACT_STATUS_SIZE             2
-#define UV_ACTIVATION_DESCRIPTOR_SIZE  32
+#define UV_ADP_SIZE                    32
 #define UV_DISTRIBUTION_SIZE           256
 #define UV_SW_ACK_NPENDING             8
 #define UV_NET_ENDPOINT_INTD           0x38
index d3a98ea1062ef936c7825f1387a4d2f4b83c65b9..341070f7ad5cb62679f22f7b3fff7316c549b5d9 100644 (file)
@@ -133,6 +133,7 @@ struct uv_scir_s {
 struct uv_hub_info_s {
        unsigned long           global_mmr_base;
        unsigned long           gpa_mask;
+       unsigned int            gnode_extra;
        unsigned long           gnode_upper;
        unsigned long           lowmem_remap_top;
        unsigned long           lowmem_remap_base;
@@ -159,7 +160,8 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
  *             p -  PNODE (local part of nsids, right shifted 1)
  */
 #define UV_NASID_TO_PNODE(n)           (((n) >> 1) & uv_hub_info->pnode_mask)
-#define UV_PNODE_TO_NASID(p)           (((p) << 1) | uv_hub_info->gnode_upper)
+#define UV_PNODE_TO_GNODE(p)           ((p) |uv_hub_info->gnode_extra)
+#define UV_PNODE_TO_NASID(p)           (UV_PNODE_TO_GNODE(p) << 1)
 
 #define UV_LOCAL_MMR_BASE              0xf4000000UL
 #define UV_GLOBAL_MMR32_BASE           0xf8000000UL
@@ -173,7 +175,7 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
 #define UV_GLOBAL_MMR32_PNODE_BITS(p)  ((p) << (UV_GLOBAL_MMR32_PNODE_SHIFT))
 
 #define UV_GLOBAL_MMR64_PNODE_BITS(p)                                  \
-       ((unsigned long)(p) << UV_GLOBAL_MMR64_PNODE_SHIFT)
+       ((unsigned long)(UV_PNODE_TO_GNODE(p)) << UV_GLOBAL_MMR64_PNODE_SHIFT)
 
 #define UV_APIC_PNODE_SHIFT    6
 
index 498f944010b9a112a013a5007a58117b66d6f6db..11be5ad2e0e9730384cacc29b96dc1d9345f728c 100644 (file)
@@ -247,6 +247,7 @@ enum vmcs_field {
 #define EXIT_REASON_MSR_READ            31
 #define EXIT_REASON_MSR_WRITE           32
 #define EXIT_REASON_MWAIT_INSTRUCTION   36
+#define EXIT_REASON_MCE_DURING_VMENTRY  41
 #define EXIT_REASON_TPR_BELOW_THRESHOLD 43
 #define EXIT_REASON_APIC_ACCESS         44
 #define EXIT_REASON_EPT_VIOLATION       48
index 88d1bfc847d30fc6b87007648fedc9970856e1af..4f78bd682125067c07fbf9c11a1b1bc1c40a2dd6 100644 (file)
@@ -28,7 +28,7 @@ CFLAGS_paravirt.o     := $(nostackp)
 obj-y                  := process_$(BITS).o signal.o entry_$(BITS).o
 obj-y                  += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
 obj-y                  += time_$(BITS).o ioport.o ldt.o dumpstack.o
-obj-y                  += setup.o i8259.o irqinit_$(BITS).o
+obj-y                  += setup.o i8259.o irqinit.o
 obj-$(CONFIG_X86_VISWS)        += visws_quirks.o
 obj-$(CONFIG_X86_32)   += probe_roms_32.o
 obj-$(CONFIG_X86_32)   += sys_i386_32.o i386_ksyms_32.o
@@ -44,6 +44,7 @@ obj-y                         += process.o
 obj-y                          += i387.o xsave.o
 obj-y                          += ptrace.o
 obj-$(CONFIG_X86_DS)           += ds.o
+obj-$(CONFIG_X86_DS_SELFTEST)          += ds_selftest.o
 obj-$(CONFIG_X86_32)           += tls.o
 obj-$(CONFIG_IA32_EMULATION)   += tls.o
 obj-y                          += step.o
index 723989d7f8029711c0a6fda92e8016101ac2ede7..631086159c53b0be5f28df92d3e2ed976cffa7a8 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/irq.h>
 #include <linux/bootmem.h>
 #include <linux/ioport.h>
+#include <linux/pci.h>
 
 #include <asm/pgtable.h>
 #include <asm/io_apic.h>
@@ -522,7 +523,7 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
  * success: return IRQ number (>=0)
  * failure: return < 0
  */
-int acpi_register_gsi(u32 gsi, int triggering, int polarity)
+int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
 {
        unsigned int irq;
        unsigned int plat_gsi = gsi;
@@ -532,14 +533,14 @@ int acpi_register_gsi(u32 gsi, int triggering, int polarity)
         * Make sure all (legacy) PCI IRQs are set as level-triggered.
         */
        if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) {
-               if (triggering == ACPI_LEVEL_SENSITIVE)
+               if (trigger == ACPI_LEVEL_SENSITIVE)
                        eisa_set_level_irq(gsi);
        }
 #endif
 
 #ifdef CONFIG_X86_IO_APIC
        if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) {
-               plat_gsi = mp_register_gsi(gsi, triggering, polarity);
+               plat_gsi = mp_register_gsi(dev, gsi, trigger, polarity);
        }
 #endif
        acpi_gsi_to_irq(plat_gsi, &irq);
@@ -903,10 +904,8 @@ extern int es7000_plat;
 #endif
 
 static struct {
-       int apic_id;
        int gsi_base;
        int gsi_end;
-       DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1);
 } mp_ioapic_routing[MAX_IO_APICS];
 
 int mp_find_ioapic(int gsi)
@@ -986,16 +985,12 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
 
        set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
        mp_ioapics[idx].apicid = uniq_ioapic_id(id);
-#ifdef CONFIG_X86_32
        mp_ioapics[idx].apicver = io_apic_get_version(idx);
-#else
-       mp_ioapics[idx].apicver = 0;
-#endif
+
        /*
         * Build basic GSI lookup table to facilitate gsi->io_apic lookups
         * and to prevent reprogramming of IOAPIC pins (PCI GSIs).
         */
-       mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].apicid;
        mp_ioapic_routing[idx].gsi_base = gsi_base;
        mp_ioapic_routing[idx].gsi_end = gsi_base +
            io_apic_get_redir_entries(idx);
@@ -1158,26 +1153,52 @@ void __init mp_config_acpi_legacy_irqs(void)
        }
 }
 
-int mp_register_gsi(u32 gsi, int triggering, int polarity)
+static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger,
+                       int polarity)
 {
+#ifdef CONFIG_X86_MPPARSE
+       struct mpc_intsrc mp_irq;
+       struct pci_dev *pdev;
+       unsigned char number;
+       unsigned int devfn;
        int ioapic;
-       int ioapic_pin;
-#ifdef CONFIG_X86_32
-#define MAX_GSI_NUM    4096
-#define IRQ_COMPRESSION_START  64
+       u8 pin;
 
-       static int pci_irq = IRQ_COMPRESSION_START;
-       /*
-        * Mapping between Global System Interrupts, which
-        * represent all possible interrupts, and IRQs
-        * assigned to actual devices.
-        */
-       static int gsi_to_irq[MAX_GSI_NUM];
-#else
+       if (!acpi_ioapic)
+               return 0;
+       if (!dev)
+               return 0;
+       if (dev->bus != &pci_bus_type)
+               return 0;
+
+       pdev = to_pci_dev(dev);
+       number = pdev->bus->number;
+       devfn = pdev->devfn;
+       pin = pdev->pin;
+       /* print the entry should happen on mptable identically */
+       mp_irq.type = MP_INTSRC;
+       mp_irq.irqtype = mp_INT;
+       mp_irq.irqflag = (trigger == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) |
+                               (polarity == ACPI_ACTIVE_HIGH ? 1 : 3);
+       mp_irq.srcbus = number;
+       mp_irq.srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3);
+       ioapic = mp_find_ioapic(gsi);
+       mp_irq.dstapic = mp_ioapics[ioapic].apicid;
+       mp_irq.dstirq = mp_find_ioapic_pin(ioapic, gsi);
+
+       save_mp_irq(&mp_irq);
+#endif
+       return 0;
+}
+
+int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
+{
+       int ioapic;
+       int ioapic_pin;
+       struct io_apic_irq_attr irq_attr;
 
        if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
                return gsi;
-#endif
 
        /* Don't set up the ACPI SCI because it's already set up */
        if (acpi_gbl_FADT.sci_interrupt == gsi)
@@ -1196,93 +1217,22 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity)
                gsi = ioapic_renumber_irq(ioapic, gsi);
 #endif
 
-       /*
-        * Avoid pin reprogramming.  PRTs typically include entries
-        * with redundant pin->gsi mappings (but unique PCI devices);
-        * we only program the IOAPIC on the first.
-        */
        if (ioapic_pin > MP_MAX_IOAPIC_PIN) {
                printk(KERN_ERR "Invalid reference to IOAPIC pin "
-                      "%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
+                      "%d-%d\n", mp_ioapics[ioapic].apicid,
                       ioapic_pin);
                return gsi;
        }
-       if (test_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed)) {
-               pr_debug("Pin %d-%d already programmed\n",
-                        mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
-#ifdef CONFIG_X86_32
-               return (gsi < IRQ_COMPRESSION_START ? gsi : gsi_to_irq[gsi]);
-#else
-               return gsi;
-#endif
-       }
-
-       set_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed);
-#ifdef CONFIG_X86_32
-       /*
-        * For GSI >= 64, use IRQ compression
-        */
-       if ((gsi >= IRQ_COMPRESSION_START)
-           && (triggering == ACPI_LEVEL_SENSITIVE)) {
-               /*
-                * For PCI devices assign IRQs in order, avoiding gaps
-                * due to unused I/O APIC pins.
-                */
-               int irq = gsi;
-               if (gsi < MAX_GSI_NUM) {
-                       /*
-                        * Retain the VIA chipset work-around (gsi > 15), but
-                        * avoid a problem where the 8254 timer (IRQ0) is setup
-                        * via an override (so it's not on pin 0 of the ioapic),
-                        * and at the same time, the pin 0 interrupt is a PCI
-                        * type.  The gsi > 15 test could cause these two pins
-                        * to be shared as IRQ0, and they are not shareable.
-                        * So test for this condition, and if necessary, avoid
-                        * the pin collision.
-                        */
-                       gsi = pci_irq++;
-                       /*
-                        * Don't assign IRQ used by ACPI SCI
-                        */
-                       if (gsi == acpi_gbl_FADT.sci_interrupt)
-                               gsi = pci_irq++;
-                       gsi_to_irq[irq] = gsi;
-               } else {
-                       printk(KERN_ERR "GSI %u is too high\n", gsi);
-                       return gsi;
-               }
-       }
-#endif
-       io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
-                               triggering == ACPI_EDGE_SENSITIVE ? 0 : 1,
-                               polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
-       return gsi;
-}
 
-int mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin,
-                       u32 gsi, int triggering, int polarity)
-{
-#ifdef CONFIG_X86_MPPARSE
-       struct mpc_intsrc mp_irq;
-       int ioapic;
+       if (enable_update_mptable)
+               mp_config_acpi_gsi(dev, gsi, trigger, polarity);
 
-       if (!acpi_ioapic)
-               return 0;
+       set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin,
+                            trigger == ACPI_EDGE_SENSITIVE ? 0 : 1,
+                            polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
+       io_apic_set_pci_routing(dev, gsi, &irq_attr);
 
-       /* print the entry should happen on mptable identically */
-       mp_irq.type = MP_INTSRC;
-       mp_irq.irqtype = mp_INT;
-       mp_irq.irqflag = (triggering == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) |
-                               (polarity == ACPI_ACTIVE_HIGH ? 1 : 3);
-       mp_irq.srcbus = number;
-       mp_irq.srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3);
-       ioapic = mp_find_ioapic(gsi);
-       mp_irq.dstapic = mp_ioapic_routing[ioapic].apic_id;
-       mp_irq.dstirq = mp_find_ioapic_pin(ioapic, gsi);
-
-       save_mp_irq(&mp_irq);
-#endif
-       return 0;
+       return gsi;
 }
 
 /*
index 1c31cc0e9def070e26288672801396d042fa604a..167bc16ce0e59ca080112db6d232f270df7ceea0 100644 (file)
@@ -9,7 +9,7 @@
 always         := wakeup.bin
 targets                := wakeup.elf wakeup.lds
 
-wakeup-y       += wakeup.o wakemain.o video-mode.o copy.o
+wakeup-y       += wakeup.o wakemain.o video-mode.o copy.o bioscall.o regs.o
 
 # The link order of the video-*.o modules can matter.  In particular,
 # video-vga.o *must* be listed first, followed by video-vesa.o.
diff --git a/arch/x86/kernel/acpi/realmode/bioscall.S b/arch/x86/kernel/acpi/realmode/bioscall.S
new file mode 100644 (file)
index 0000000..f51eb0b
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../boot/bioscall.S"
diff --git a/arch/x86/kernel/acpi/realmode/regs.c b/arch/x86/kernel/acpi/realmode/regs.c
new file mode 100644 (file)
index 0000000..6206033
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../boot/regs.c"
index a97db99dad52fedd4bbcf6fe9d46bed8784f5e1f..1c60554537c358ef37fa9352e5bfd624dadf3e1a 100644 (file)
@@ -55,7 +55,16 @@ struct iommu_cmd {
 static int dma_ops_unity_map(struct dma_ops_domain *dma_dom,
                             struct unity_map_entry *e);
 static struct dma_ops_domain *find_protection_domain(u16 devid);
+static u64* alloc_pte(struct protection_domain *dom,
+                     unsigned long address, u64
+                     **pte_page, gfp_t gfp);
+static void dma_ops_reserve_addresses(struct dma_ops_domain *dom,
+                                     unsigned long start_page,
+                                     unsigned int pages);
 
+#ifndef BUS_NOTIFY_UNBOUND_DRIVER
+#define BUS_NOTIFY_UNBOUND_DRIVER 0x0005
+#endif
 
 #ifdef CONFIG_AMD_IOMMU_STATS
 
@@ -213,7 +222,7 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data)
 {
        struct amd_iommu *iommu;
 
-       list_for_each_entry(iommu, &amd_iommu_list, list)
+       for_each_iommu(iommu)
                iommu_poll_events(iommu);
 
        return IRQ_HANDLED;
@@ -440,7 +449,7 @@ static void iommu_flush_domain(u16 domid)
        __iommu_build_inv_iommu_pages(&cmd, CMD_INV_IOMMU_ALL_PAGES_ADDRESS,
                                      domid, 1, 1);
 
-       list_for_each_entry(iommu, &amd_iommu_list, list) {
+       for_each_iommu(iommu) {
                spin_lock_irqsave(&iommu->lock, flags);
                __iommu_queue_command(iommu, &cmd);
                __iommu_completion_wait(iommu);
@@ -449,6 +458,35 @@ static void iommu_flush_domain(u16 domid)
        }
 }
 
+void amd_iommu_flush_all_domains(void)
+{
+       int i;
+
+       for (i = 1; i < MAX_DOMAIN_ID; ++i) {
+               if (!test_bit(i, amd_iommu_pd_alloc_bitmap))
+                       continue;
+               iommu_flush_domain(i);
+       }
+}
+
+void amd_iommu_flush_all_devices(void)
+{
+       struct amd_iommu *iommu;
+       int i;
+
+       for (i = 0; i <= amd_iommu_last_bdf; ++i) {
+               if (amd_iommu_pd_table[i] == NULL)
+                       continue;
+
+               iommu = amd_iommu_rlookup_table[i];
+               if (!iommu)
+                       continue;
+
+               iommu_queue_inv_dev_entry(iommu, i);
+               iommu_completion_wait(iommu);
+       }
+}
+
 /****************************************************************************
  *
  * The functions below are used the create the page table mappings for
@@ -468,7 +506,7 @@ static int iommu_map_page(struct protection_domain *dom,
                          unsigned long phys_addr,
                          int prot)
 {
-       u64 __pte, *pte, *page;
+       u64 __pte, *pte;
 
        bus_addr  = PAGE_ALIGN(bus_addr);
        phys_addr = PAGE_ALIGN(phys_addr);
@@ -477,27 +515,7 @@ static int iommu_map_page(struct protection_domain *dom,
        if (bus_addr > IOMMU_MAP_SIZE_L3 || !(prot & IOMMU_PROT_MASK))
                return -EINVAL;
 
-       pte = &dom->pt_root[IOMMU_PTE_L2_INDEX(bus_addr)];
-
-       if (!IOMMU_PTE_PRESENT(*pte)) {
-               page = (u64 *)get_zeroed_page(GFP_KERNEL);
-               if (!page)
-                       return -ENOMEM;
-               *pte = IOMMU_L2_PDE(virt_to_phys(page));
-       }
-
-       pte = IOMMU_PTE_PAGE(*pte);
-       pte = &pte[IOMMU_PTE_L1_INDEX(bus_addr)];
-
-       if (!IOMMU_PTE_PRESENT(*pte)) {
-               page = (u64 *)get_zeroed_page(GFP_KERNEL);
-               if (!page)
-                       return -ENOMEM;
-               *pte = IOMMU_L1_PDE(virt_to_phys(page));
-       }
-
-       pte = IOMMU_PTE_PAGE(*pte);
-       pte = &pte[IOMMU_PTE_L0_INDEX(bus_addr)];
+       pte = alloc_pte(dom, bus_addr, NULL, GFP_KERNEL);
 
        if (IOMMU_PTE_PRESENT(*pte))
                return -EBUSY;
@@ -595,7 +613,8 @@ static int dma_ops_unity_map(struct dma_ops_domain *dma_dom,
                 * as allocated in the aperture
                 */
                if (addr < dma_dom->aperture_size)
-                       __set_bit(addr >> PAGE_SHIFT, dma_dom->bitmap);
+                       __set_bit(addr >> PAGE_SHIFT,
+                                 dma_dom->aperture[0]->bitmap);
        }
 
        return 0;
@@ -632,42 +651,191 @@ static int init_unity_mappings_for_device(struct dma_ops_domain *dma_dom,
  ****************************************************************************/
 
 /*
- * The address allocator core function.
+ * The address allocator core functions.
  *
  * called with domain->lock held
  */
+
+/*
+ * This function checks if there is a PTE for a given dma address. If
+ * there is one, it returns the pointer to it.
+ */
+static u64* fetch_pte(struct protection_domain *domain,
+                     unsigned long address)
+{
+       u64 *pte;
+
+       pte = &domain->pt_root[IOMMU_PTE_L2_INDEX(address)];
+
+       if (!IOMMU_PTE_PRESENT(*pte))
+               return NULL;
+
+       pte = IOMMU_PTE_PAGE(*pte);
+       pte = &pte[IOMMU_PTE_L1_INDEX(address)];
+
+       if (!IOMMU_PTE_PRESENT(*pte))
+               return NULL;
+
+       pte = IOMMU_PTE_PAGE(*pte);
+       pte = &pte[IOMMU_PTE_L0_INDEX(address)];
+
+       return pte;
+}
+
+/*
+ * This function is used to add a new aperture range to an existing
+ * aperture in case of dma_ops domain allocation or address allocation
+ * failure.
+ */
+static int alloc_new_range(struct amd_iommu *iommu,
+                          struct dma_ops_domain *dma_dom,
+                          bool populate, gfp_t gfp)
+{
+       int index = dma_dom->aperture_size >> APERTURE_RANGE_SHIFT;
+       int i;
+
+#ifdef CONFIG_IOMMU_STRESS
+       populate = false;
+#endif
+
+       if (index >= APERTURE_MAX_RANGES)
+               return -ENOMEM;
+
+       dma_dom->aperture[index] = kzalloc(sizeof(struct aperture_range), gfp);
+       if (!dma_dom->aperture[index])
+               return -ENOMEM;
+
+       dma_dom->aperture[index]->bitmap = (void *)get_zeroed_page(gfp);
+       if (!dma_dom->aperture[index]->bitmap)
+               goto out_free;
+
+       dma_dom->aperture[index]->offset = dma_dom->aperture_size;
+
+       if (populate) {
+               unsigned long address = dma_dom->aperture_size;
+               int i, num_ptes = APERTURE_RANGE_PAGES / 512;
+               u64 *pte, *pte_page;
+
+               for (i = 0; i < num_ptes; ++i) {
+                       pte = alloc_pte(&dma_dom->domain, address,
+                                       &pte_page, gfp);
+                       if (!pte)
+                               goto out_free;
+
+                       dma_dom->aperture[index]->pte_pages[i] = pte_page;
+
+                       address += APERTURE_RANGE_SIZE / 64;
+               }
+       }
+
+       dma_dom->aperture_size += APERTURE_RANGE_SIZE;
+
+       /* Intialize the exclusion range if necessary */
+       if (iommu->exclusion_start &&
+           iommu->exclusion_start >= dma_dom->aperture[index]->offset &&
+           iommu->exclusion_start < dma_dom->aperture_size) {
+               unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT;
+               int pages = iommu_num_pages(iommu->exclusion_start,
+                                           iommu->exclusion_length,
+                                           PAGE_SIZE);
+               dma_ops_reserve_addresses(dma_dom, startpage, pages);
+       }
+
+       /*
+        * Check for areas already mapped as present in the new aperture
+        * range and mark those pages as reserved in the allocator. Such
+        * mappings may already exist as a result of requested unity
+        * mappings for devices.
+        */
+       for (i = dma_dom->aperture[index]->offset;
+            i < dma_dom->aperture_size;
+            i += PAGE_SIZE) {
+               u64 *pte = fetch_pte(&dma_dom->domain, i);
+               if (!pte || !IOMMU_PTE_PRESENT(*pte))
+                       continue;
+
+               dma_ops_reserve_addresses(dma_dom, i << PAGE_SHIFT, 1);
+       }
+
+       return 0;
+
+out_free:
+       free_page((unsigned long)dma_dom->aperture[index]->bitmap);
+
+       kfree(dma_dom->aperture[index]);
+       dma_dom->aperture[index] = NULL;
+
+       return -ENOMEM;
+}
+
+static unsigned long dma_ops_area_alloc(struct device *dev,
+                                       struct dma_ops_domain *dom,
+                                       unsigned int pages,
+                                       unsigned long align_mask,
+                                       u64 dma_mask,
+                                       unsigned long start)
+{
+       unsigned long next_bit = dom->next_address % APERTURE_RANGE_SIZE;
+       int max_index = dom->aperture_size >> APERTURE_RANGE_SHIFT;
+       int i = start >> APERTURE_RANGE_SHIFT;
+       unsigned long boundary_size;
+       unsigned long address = -1;
+       unsigned long limit;
+
+       next_bit >>= PAGE_SHIFT;
+
+       boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+                       PAGE_SIZE) >> PAGE_SHIFT;
+
+       for (;i < max_index; ++i) {
+               unsigned long offset = dom->aperture[i]->offset >> PAGE_SHIFT;
+
+               if (dom->aperture[i]->offset >= dma_mask)
+                       break;
+
+               limit = iommu_device_max_index(APERTURE_RANGE_PAGES, offset,
+                                              dma_mask >> PAGE_SHIFT);
+
+               address = iommu_area_alloc(dom->aperture[i]->bitmap,
+                                          limit, next_bit, pages, 0,
+                                           boundary_size, align_mask);
+               if (address != -1) {
+                       address = dom->aperture[i]->offset +
+                                 (address << PAGE_SHIFT);
+                       dom->next_address = address + (pages << PAGE_SHIFT);
+                       break;
+               }
+
+               next_bit = 0;
+       }
+
+       return address;
+}
+
 static unsigned long dma_ops_alloc_addresses(struct device *dev,
                                             struct dma_ops_domain *dom,
                                             unsigned int pages,
                                             unsigned long align_mask,
                                             u64 dma_mask)
 {
-       unsigned long limit;
        unsigned long address;
-       unsigned long boundary_size;
 
-       boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
-                       PAGE_SIZE) >> PAGE_SHIFT;
-       limit = iommu_device_max_index(dom->aperture_size >> PAGE_SHIFT, 0,
-                                      dma_mask >> PAGE_SHIFT);
+#ifdef CONFIG_IOMMU_STRESS
+       dom->next_address = 0;
+       dom->need_flush = true;
+#endif
 
-       if (dom->next_bit >= limit) {
-               dom->next_bit = 0;
-               dom->need_flush = true;
-       }
+       address = dma_ops_area_alloc(dev, dom, pages, align_mask,
+                                    dma_mask, dom->next_address);
 
-       address = iommu_area_alloc(dom->bitmap, limit, dom->next_bit, pages,
-                                  0 , boundary_size, align_mask);
        if (address == -1) {
-               address = iommu_area_alloc(dom->bitmap, limit, 0, pages,
-                               0, boundary_size, align_mask);
+               dom->next_address = 0;
+               address = dma_ops_area_alloc(dev, dom, pages, align_mask,
+                                            dma_mask, 0);
                dom->need_flush = true;
        }
 
-       if (likely(address != -1)) {
-               dom->next_bit = address + pages;
-               address <<= PAGE_SHIFT;
-       } else
+       if (unlikely(address == -1))
                address = bad_dma_address;
 
        WARN_ON((address + (PAGE_SIZE*pages)) > dom->aperture_size);
@@ -684,11 +852,23 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom,
                                   unsigned long address,
                                   unsigned int pages)
 {
-       address >>= PAGE_SHIFT;
-       iommu_area_free(dom->bitmap, address, pages);
+       unsigned i = address >> APERTURE_RANGE_SHIFT;
+       struct aperture_range *range = dom->aperture[i];
 
-       if (address >= dom->next_bit)
+       BUG_ON(i >= APERTURE_MAX_RANGES || range == NULL);
+
+#ifdef CONFIG_IOMMU_STRESS
+       if (i < 4)
+               return;
+#endif
+
+       if (address >= dom->next_address)
                dom->need_flush = true;
+
+       address = (address % APERTURE_RANGE_SIZE) >> PAGE_SHIFT;
+
+       iommu_area_free(range->bitmap, address, pages);
+
 }
 
 /****************************************************************************
@@ -736,12 +916,16 @@ static void dma_ops_reserve_addresses(struct dma_ops_domain *dom,
                                      unsigned long start_page,
                                      unsigned int pages)
 {
-       unsigned int last_page = dom->aperture_size >> PAGE_SHIFT;
+       unsigned int i, last_page = dom->aperture_size >> PAGE_SHIFT;
 
        if (start_page + pages > last_page)
                pages = last_page - start_page;
 
-       iommu_area_reserve(dom->bitmap, start_page, pages);
+       for (i = start_page; i < start_page + pages; ++i) {
+               int index = i / APERTURE_RANGE_PAGES;
+               int page  = i % APERTURE_RANGE_PAGES;
+               __set_bit(page, dom->aperture[index]->bitmap);
+       }
 }
 
 static void free_pagetable(struct protection_domain *domain)
@@ -780,14 +964,19 @@ static void free_pagetable(struct protection_domain *domain)
  */
 static void dma_ops_domain_free(struct dma_ops_domain *dom)
 {
+       int i;
+
        if (!dom)
                return;
 
        free_pagetable(&dom->domain);
 
-       kfree(dom->pte_pages);
-
-       kfree(dom->bitmap);
+       for (i = 0; i < APERTURE_MAX_RANGES; ++i) {
+               if (!dom->aperture[i])
+                       continue;
+               free_page((unsigned long)dom->aperture[i]->bitmap);
+               kfree(dom->aperture[i]);
+       }
 
        kfree(dom);
 }
@@ -797,19 +986,9 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom)
  * It also intializes the page table and the address allocator data
  * structures required for the dma_ops interface
  */
-static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
-                                                  unsigned order)
+static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu)
 {
        struct dma_ops_domain *dma_dom;
-       unsigned i, num_pte_pages;
-       u64 *l2_pde;
-       u64 address;
-
-       /*
-        * Currently the DMA aperture must be between 32 MB and 1GB in size
-        */
-       if ((order < 25) || (order > 30))
-               return NULL;
 
        dma_dom = kzalloc(sizeof(struct dma_ops_domain), GFP_KERNEL);
        if (!dma_dom)
@@ -826,55 +1005,20 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
        dma_dom->domain.priv = dma_dom;
        if (!dma_dom->domain.pt_root)
                goto free_dma_dom;
-       dma_dom->aperture_size = (1ULL << order);
-       dma_dom->bitmap = kzalloc(dma_dom->aperture_size / (PAGE_SIZE * 8),
-                                 GFP_KERNEL);
-       if (!dma_dom->bitmap)
-               goto free_dma_dom;
-       /*
-        * mark the first page as allocated so we never return 0 as
-        * a valid dma-address. So we can use 0 as error value
-        */
-       dma_dom->bitmap[0] = 1;
-       dma_dom->next_bit = 0;
 
        dma_dom->need_flush = false;
        dma_dom->target_dev = 0xffff;
 
-       /* Intialize the exclusion range if necessary */
-       if (iommu->exclusion_start &&
-           iommu->exclusion_start < dma_dom->aperture_size) {
-               unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT;
-               int pages = iommu_num_pages(iommu->exclusion_start,
-                                           iommu->exclusion_length,
-                                           PAGE_SIZE);
-               dma_ops_reserve_addresses(dma_dom, startpage, pages);
-       }
+       if (alloc_new_range(iommu, dma_dom, true, GFP_KERNEL))
+               goto free_dma_dom;
 
        /*
-        * At the last step, build the page tables so we don't need to
-        * allocate page table pages in the dma_ops mapping/unmapping
-        * path.
+        * mark the first page as allocated so we never return 0 as
+        * a valid dma-address. So we can use 0 as error value
         */
-       num_pte_pages = dma_dom->aperture_size / (PAGE_SIZE * 512);
-       dma_dom->pte_pages = kzalloc(num_pte_pages * sizeof(void *),
-                       GFP_KERNEL);
-       if (!dma_dom->pte_pages)
-               goto free_dma_dom;
-
-       l2_pde = (u64 *)get_zeroed_page(GFP_KERNEL);
-       if (l2_pde == NULL)
-               goto free_dma_dom;
+       dma_dom->aperture[0]->bitmap[0] = 1;
+       dma_dom->next_address = 0;
 
-       dma_dom->domain.pt_root[0] = IOMMU_L2_PDE(virt_to_phys(l2_pde));
-
-       for (i = 0; i < num_pte_pages; ++i) {
-               dma_dom->pte_pages[i] = (u64 *)get_zeroed_page(GFP_KERNEL);
-               if (!dma_dom->pte_pages[i])
-                       goto free_dma_dom;
-               address = virt_to_phys(dma_dom->pte_pages[i]);
-               l2_pde[i] = IOMMU_L1_PDE(address);
-       }
 
        return dma_dom;
 
@@ -983,7 +1127,6 @@ static int device_change_notifier(struct notifier_block *nb,
        struct protection_domain *domain;
        struct dma_ops_domain *dma_domain;
        struct amd_iommu *iommu;
-       int order = amd_iommu_aperture_order;
        unsigned long flags;
 
        if (devid > amd_iommu_last_bdf)
@@ -1002,17 +1145,7 @@ static int device_change_notifier(struct notifier_block *nb,
                          "to a non-dma-ops domain\n", dev_name(dev));
 
        switch (action) {
-       case BUS_NOTIFY_BOUND_DRIVER:
-               if (domain)
-                       goto out;
-               dma_domain = find_protection_domain(devid);
-               if (!dma_domain)
-                       dma_domain = iommu->default_dom;
-               attach_device(iommu, &dma_domain->domain, devid);
-               printk(KERN_INFO "AMD IOMMU: Using protection domain %d for "
-                      "device %s\n", dma_domain->domain.id, dev_name(dev));
-               break;
-       case BUS_NOTIFY_UNBIND_DRIVER:
+       case BUS_NOTIFY_UNBOUND_DRIVER:
                if (!domain)
                        goto out;
                detach_device(domain, devid);
@@ -1022,7 +1155,7 @@ static int device_change_notifier(struct notifier_block *nb,
                dma_domain = find_protection_domain(devid);
                if (dma_domain)
                        goto out;
-               dma_domain = dma_ops_domain_alloc(iommu, order);
+               dma_domain = dma_ops_domain_alloc(iommu);
                if (!dma_domain)
                        goto out;
                dma_domain->target_dev = devid;
@@ -1133,8 +1266,8 @@ static int get_device_resources(struct device *dev,
                        dma_dom = (*iommu)->default_dom;
                *domain = &dma_dom->domain;
                attach_device(*iommu, *domain, *bdf);
-               printk(KERN_INFO "AMD IOMMU: Using protection domain %d for "
-                               "device %s\n", (*domain)->id, dev_name(dev));
+               DUMP_printk("Using protection domain %d for device %s\n",
+                           (*domain)->id, dev_name(dev));
        }
 
        if (domain_for_device(_bdf) == NULL)
@@ -1143,6 +1276,66 @@ static int get_device_resources(struct device *dev,
        return 1;
 }
 
+/*
+ * If the pte_page is not yet allocated this function is called
+ */
+static u64* alloc_pte(struct protection_domain *dom,
+                     unsigned long address, u64 **pte_page, gfp_t gfp)
+{
+       u64 *pte, *page;
+
+       pte = &dom->pt_root[IOMMU_PTE_L2_INDEX(address)];
+
+       if (!IOMMU_PTE_PRESENT(*pte)) {
+               page = (u64 *)get_zeroed_page(gfp);
+               if (!page)
+                       return NULL;
+               *pte = IOMMU_L2_PDE(virt_to_phys(page));
+       }
+
+       pte = IOMMU_PTE_PAGE(*pte);
+       pte = &pte[IOMMU_PTE_L1_INDEX(address)];
+
+       if (!IOMMU_PTE_PRESENT(*pte)) {
+               page = (u64 *)get_zeroed_page(gfp);
+               if (!page)
+                       return NULL;
+               *pte = IOMMU_L1_PDE(virt_to_phys(page));
+       }
+
+       pte = IOMMU_PTE_PAGE(*pte);
+
+       if (pte_page)
+               *pte_page = pte;
+
+       pte = &pte[IOMMU_PTE_L0_INDEX(address)];
+
+       return pte;
+}
+
+/*
+ * This function fetches the PTE for a given address in the aperture
+ */
+static u64* dma_ops_get_pte(struct dma_ops_domain *dom,
+                           unsigned long address)
+{
+       struct aperture_range *aperture;
+       u64 *pte, *pte_page;
+
+       aperture = dom->aperture[APERTURE_RANGE_INDEX(address)];
+       if (!aperture)
+               return NULL;
+
+       pte = aperture->pte_pages[APERTURE_PAGE_INDEX(address)];
+       if (!pte) {
+               pte = alloc_pte(&dom->domain, address, &pte_page, GFP_ATOMIC);
+               aperture->pte_pages[APERTURE_PAGE_INDEX(address)] = pte_page;
+       } else
+               pte += IOMMU_PTE_L0_INDEX(address);
+
+       return pte;
+}
+
 /*
  * This is the generic map function. It maps one 4kb page at paddr to
  * the given address in the DMA address space for the domain.
@@ -1159,8 +1352,9 @@ static dma_addr_t dma_ops_domain_map(struct amd_iommu *iommu,
 
        paddr &= PAGE_MASK;
 
-       pte  = dom->pte_pages[IOMMU_PTE_L1_INDEX(address)];
-       pte += IOMMU_PTE_L0_INDEX(address);
+       pte  = dma_ops_get_pte(dom, address);
+       if (!pte)
+               return bad_dma_address;
 
        __pte = paddr | IOMMU_PTE_P | IOMMU_PTE_FC;
 
@@ -1185,14 +1379,20 @@ static void dma_ops_domain_unmap(struct amd_iommu *iommu,
                                 struct dma_ops_domain *dom,
                                 unsigned long address)
 {
+       struct aperture_range *aperture;
        u64 *pte;
 
        if (address >= dom->aperture_size)
                return;
 
-       WARN_ON(address & ~PAGE_MASK || address >= dom->aperture_size);
+       aperture = dom->aperture[APERTURE_RANGE_INDEX(address)];
+       if (!aperture)
+               return;
+
+       pte  = aperture->pte_pages[APERTURE_PAGE_INDEX(address)];
+       if (!pte)
+               return;
 
-       pte  = dom->pte_pages[IOMMU_PTE_L1_INDEX(address)];
        pte += IOMMU_PTE_L0_INDEX(address);
 
        WARN_ON(!*pte);
@@ -1216,7 +1416,7 @@ static dma_addr_t __map_single(struct device *dev,
                               u64 dma_mask)
 {
        dma_addr_t offset = paddr & ~PAGE_MASK;
-       dma_addr_t address, start;
+       dma_addr_t address, start, ret;
        unsigned int pages;
        unsigned long align_mask = 0;
        int i;
@@ -1232,14 +1432,33 @@ static dma_addr_t __map_single(struct device *dev,
        if (align)
                align_mask = (1UL << get_order(size)) - 1;
 
+retry:
        address = dma_ops_alloc_addresses(dev, dma_dom, pages, align_mask,
                                          dma_mask);
-       if (unlikely(address == bad_dma_address))
-               goto out;
+       if (unlikely(address == bad_dma_address)) {
+               /*
+                * setting next_address here will let the address
+                * allocator only scan the new allocated range in the
+                * first run. This is a small optimization.
+                */
+               dma_dom->next_address = dma_dom->aperture_size;
+
+               if (alloc_new_range(iommu, dma_dom, false, GFP_ATOMIC))
+                       goto out;
+
+               /*
+                * aperture was sucessfully enlarged by 128 MB, try
+                * allocation again
+                */
+               goto retry;
+       }
 
        start = address;
        for (i = 0; i < pages; ++i) {
-               dma_ops_domain_map(iommu, dma_dom, start, paddr, dir);
+               ret = dma_ops_domain_map(iommu, dma_dom, start, paddr, dir);
+               if (ret == bad_dma_address)
+                       goto out_unmap;
+
                paddr += PAGE_SIZE;
                start += PAGE_SIZE;
        }
@@ -1255,6 +1474,17 @@ static dma_addr_t __map_single(struct device *dev,
 
 out:
        return address;
+
+out_unmap:
+
+       for (--i; i >= 0; --i) {
+               start -= PAGE_SIZE;
+               dma_ops_domain_unmap(iommu, dma_dom, start);
+       }
+
+       dma_ops_free_addresses(dma_dom, address, pages);
+
+       return bad_dma_address;
 }
 
 /*
@@ -1537,8 +1767,10 @@ static void *alloc_coherent(struct device *dev, size_t size,
        *dma_addr = __map_single(dev, iommu, domain->priv, paddr,
                                 size, DMA_BIDIRECTIONAL, true, dma_mask);
 
-       if (*dma_addr == bad_dma_address)
+       if (*dma_addr == bad_dma_address) {
+               spin_unlock_irqrestore(&domain->lock, flags);
                goto out_free;
+       }
 
        iommu_completion_wait(iommu);
 
@@ -1625,7 +1857,6 @@ static void prealloc_protection_domains(void)
        struct pci_dev *dev = NULL;
        struct dma_ops_domain *dma_dom;
        struct amd_iommu *iommu;
-       int order = amd_iommu_aperture_order;
        u16 devid;
 
        while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
@@ -1638,7 +1869,7 @@ static void prealloc_protection_domains(void)
                iommu = amd_iommu_rlookup_table[devid];
                if (!iommu)
                        continue;
-               dma_dom = dma_ops_domain_alloc(iommu, order);
+               dma_dom = dma_ops_domain_alloc(iommu);
                if (!dma_dom)
                        continue;
                init_unity_mappings_for_device(dma_dom, devid);
@@ -1664,7 +1895,6 @@ static struct dma_map_ops amd_iommu_dma_ops = {
 int __init amd_iommu_init_dma_ops(void)
 {
        struct amd_iommu *iommu;
-       int order = amd_iommu_aperture_order;
        int ret;
 
        /*
@@ -1672,8 +1902,8 @@ int __init amd_iommu_init_dma_ops(void)
         * found in the system. Devices not assigned to any other
         * protection domain will be assigned to the default one.
         */
-       list_for_each_entry(iommu, &amd_iommu_list, list) {
-               iommu->default_dom = dma_ops_domain_alloc(iommu, order);
+       for_each_iommu(iommu) {
+               iommu->default_dom = dma_ops_domain_alloc(iommu);
                if (iommu->default_dom == NULL)
                        return -ENOMEM;
                iommu->default_dom->domain.flags |= PD_DEFAULT_MASK;
@@ -1710,7 +1940,7 @@ int __init amd_iommu_init_dma_ops(void)
 
 free_domains:
 
-       list_for_each_entry(iommu, &amd_iommu_list, list) {
+       for_each_iommu(iommu) {
                if (iommu->default_dom)
                        dma_ops_domain_free(iommu->default_dom);
        }
@@ -1842,7 +2072,7 @@ static int amd_iommu_attach_device(struct iommu_domain *dom,
 
        old_domain = domain_for_device(devid);
        if (old_domain)
-               return -EBUSY;
+               detach_device(old_domain, devid);
 
        attach_device(iommu, domain, devid);
 
index 8c0be0902dacb2cc4e766cbe851891bd889f08e7..238989ec077df9e0b669c2f2a65d8b820a833510 100644 (file)
@@ -115,15 +115,21 @@ struct ivmd_header {
        u64 range_length;
 } __attribute__((packed));
 
+bool amd_iommu_dump;
+
 static int __initdata amd_iommu_detected;
 
 u16 amd_iommu_last_bdf;                        /* largest PCI device id we have
                                           to handle */
 LIST_HEAD(amd_iommu_unity_map);                /* a list of required unity mappings
                                           we find in ACPI */
-unsigned amd_iommu_aperture_order = 26; /* size of aperture in power of 2 */
+#ifdef CONFIG_IOMMU_STRESS
+bool amd_iommu_isolate = false;
+#else
 bool amd_iommu_isolate = true;         /* if true, device isolation is
                                           enabled */
+#endif
+
 bool amd_iommu_unmap_flush;            /* if true, flush on every unmap */
 
 LIST_HEAD(amd_iommu_list);             /* list of all AMD IOMMUs in the
@@ -175,7 +181,7 @@ static inline void update_last_devid(u16 devid)
 static inline unsigned long tbl_size(int entry_size)
 {
        unsigned shift = PAGE_SHIFT +
-                        get_order(amd_iommu_last_bdf * entry_size);
+                        get_order(((int)amd_iommu_last_bdf + 1) * entry_size);
 
        return 1UL << shift;
 }
@@ -193,7 +199,7 @@ static inline unsigned long tbl_size(int entry_size)
  * This function set the exclusion range in the IOMMU. DMA accesses to the
  * exclusion range are passed through untranslated
  */
-static void __init iommu_set_exclusion_range(struct amd_iommu *iommu)
+static void iommu_set_exclusion_range(struct amd_iommu *iommu)
 {
        u64 start = iommu->exclusion_start & PAGE_MASK;
        u64 limit = (start + iommu->exclusion_length) & PAGE_MASK;
@@ -225,7 +231,7 @@ static void __init iommu_set_device_table(struct amd_iommu *iommu)
 }
 
 /* Generic functions to enable/disable certain features of the IOMMU. */
-static void __init iommu_feature_enable(struct amd_iommu *iommu, u8 bit)
+static void iommu_feature_enable(struct amd_iommu *iommu, u8 bit)
 {
        u32 ctrl;
 
@@ -244,7 +250,7 @@ static void __init iommu_feature_disable(struct amd_iommu *iommu, u8 bit)
 }
 
 /* Function to enable the hardware */
-static void __init iommu_enable(struct amd_iommu *iommu)
+static void iommu_enable(struct amd_iommu *iommu)
 {
        printk(KERN_INFO "AMD IOMMU: Enabling IOMMU at %s cap 0x%hx\n",
               dev_name(&iommu->dev->dev), iommu->cap_ptr);
@@ -252,11 +258,9 @@ static void __init iommu_enable(struct amd_iommu *iommu)
        iommu_feature_enable(iommu, CONTROL_IOMMU_EN);
 }
 
-/* Function to enable IOMMU event logging and event interrupts */
-static void __init iommu_enable_event_logging(struct amd_iommu *iommu)
+static void iommu_disable(struct amd_iommu *iommu)
 {
-       iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN);
-       iommu_feature_enable(iommu, CONTROL_EVT_INT_EN);
+       iommu_feature_disable(iommu, CONTROL_IOMMU_EN);
 }
 
 /*
@@ -413,25 +417,36 @@ static u8 * __init alloc_command_buffer(struct amd_iommu *iommu)
 {
        u8 *cmd_buf = (u8 *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
                        get_order(CMD_BUFFER_SIZE));
-       u64 entry;
 
        if (cmd_buf == NULL)
                return NULL;
 
        iommu->cmd_buf_size = CMD_BUFFER_SIZE;
 
-       entry = (u64)virt_to_phys(cmd_buf);
+       return cmd_buf;
+}
+
+/*
+ * This function writes the command buffer address to the hardware and
+ * enables it.
+ */
+static void iommu_enable_command_buffer(struct amd_iommu *iommu)
+{
+       u64 entry;
+
+       BUG_ON(iommu->cmd_buf == NULL);
+
+       entry = (u64)virt_to_phys(iommu->cmd_buf);
        entry |= MMIO_CMD_SIZE_512;
+
        memcpy_toio(iommu->mmio_base + MMIO_CMD_BUF_OFFSET,
-                       &entry, sizeof(entry));
+                   &entry, sizeof(entry));
 
        /* set head and tail to zero manually */
        writel(0x00, iommu->mmio_base + MMIO_CMD_HEAD_OFFSET);
        writel(0x00, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
 
        iommu_feature_enable(iommu, CONTROL_CMDBUF_EN);
-
-       return cmd_buf;
 }
 
 static void __init free_command_buffer(struct amd_iommu *iommu)
@@ -443,20 +458,27 @@ static void __init free_command_buffer(struct amd_iommu *iommu)
 /* allocates the memory where the IOMMU will log its events to */
 static u8 * __init alloc_event_buffer(struct amd_iommu *iommu)
 {
-       u64 entry;
        iommu->evt_buf = (u8 *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
                                                get_order(EVT_BUFFER_SIZE));
 
        if (iommu->evt_buf == NULL)
                return NULL;
 
+       return iommu->evt_buf;
+}
+
+static void iommu_enable_event_buffer(struct amd_iommu *iommu)
+{
+       u64 entry;
+
+       BUG_ON(iommu->evt_buf == NULL);
+
        entry = (u64)virt_to_phys(iommu->evt_buf) | EVT_LEN_MASK;
+
        memcpy_toio(iommu->mmio_base + MMIO_EVT_BUF_OFFSET,
                    &entry, sizeof(entry));
 
-       iommu->evt_buf_size = EVT_BUFFER_SIZE;
-
-       return iommu->evt_buf;
+       iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN);
 }
 
 static void __init free_event_buffer(struct amd_iommu *iommu)
@@ -596,32 +618,83 @@ static void __init init_iommu_from_acpi(struct amd_iommu *iommu,
        p += sizeof(struct ivhd_header);
        end += h->length;
 
+
        while (p < end) {
                e = (struct ivhd_entry *)p;
                switch (e->type) {
                case IVHD_DEV_ALL:
+
+                       DUMP_printk("  DEV_ALL\t\t\t first devid: %02x:%02x.%x"
+                                   " last device %02x:%02x.%x flags: %02x\n",
+                                   PCI_BUS(iommu->first_device),
+                                   PCI_SLOT(iommu->first_device),
+                                   PCI_FUNC(iommu->first_device),
+                                   PCI_BUS(iommu->last_device),
+                                   PCI_SLOT(iommu->last_device),
+                                   PCI_FUNC(iommu->last_device),
+                                   e->flags);
+
                        for (dev_i = iommu->first_device;
                                        dev_i <= iommu->last_device; ++dev_i)
                                set_dev_entry_from_acpi(iommu, dev_i,
                                                        e->flags, 0);
                        break;
                case IVHD_DEV_SELECT:
+
+                       DUMP_printk("  DEV_SELECT\t\t\t devid: %02x:%02x.%x "
+                                   "flags: %02x\n",
+                                   PCI_BUS(e->devid),
+                                   PCI_SLOT(e->devid),
+                                   PCI_FUNC(e->devid),
+                                   e->flags);
+
                        devid = e->devid;
                        set_dev_entry_from_acpi(iommu, devid, e->flags, 0);
                        break;
                case IVHD_DEV_SELECT_RANGE_START:
+
+                       DUMP_printk("  DEV_SELECT_RANGE_START\t "
+                                   "devid: %02x:%02x.%x flags: %02x\n",
+                                   PCI_BUS(e->devid),
+                                   PCI_SLOT(e->devid),
+                                   PCI_FUNC(e->devid),
+                                   e->flags);
+
                        devid_start = e->devid;
                        flags = e->flags;
                        ext_flags = 0;
                        alias = false;
                        break;
                case IVHD_DEV_ALIAS:
+
+                       DUMP_printk("  DEV_ALIAS\t\t\t devid: %02x:%02x.%x "
+                                   "flags: %02x devid_to: %02x:%02x.%x\n",
+                                   PCI_BUS(e->devid),
+                                   PCI_SLOT(e->devid),
+                                   PCI_FUNC(e->devid),
+                                   e->flags,
+                                   PCI_BUS(e->ext >> 8),
+                                   PCI_SLOT(e->ext >> 8),
+                                   PCI_FUNC(e->ext >> 8));
+
                        devid = e->devid;
                        devid_to = e->ext >> 8;
-                       set_dev_entry_from_acpi(iommu, devid, e->flags, 0);
+                       set_dev_entry_from_acpi(iommu, devid_to, e->flags, 0);
                        amd_iommu_alias_table[devid] = devid_to;
                        break;
                case IVHD_DEV_ALIAS_RANGE:
+
+                       DUMP_printk("  DEV_ALIAS_RANGE\t\t "
+                                   "devid: %02x:%02x.%x flags: %02x "
+                                   "devid_to: %02x:%02x.%x\n",
+                                   PCI_BUS(e->devid),
+                                   PCI_SLOT(e->devid),
+                                   PCI_FUNC(e->devid),
+                                   e->flags,
+                                   PCI_BUS(e->ext >> 8),
+                                   PCI_SLOT(e->ext >> 8),
+                                   PCI_FUNC(e->ext >> 8));
+
                        devid_start = e->devid;
                        flags = e->flags;
                        devid_to = e->ext >> 8;
@@ -629,17 +702,39 @@ static void __init init_iommu_from_acpi(struct amd_iommu *iommu,
                        alias = true;
                        break;
                case IVHD_DEV_EXT_SELECT:
+
+                       DUMP_printk("  DEV_EXT_SELECT\t\t devid: %02x:%02x.%x "
+                                   "flags: %02x ext: %08x\n",
+                                   PCI_BUS(e->devid),
+                                   PCI_SLOT(e->devid),
+                                   PCI_FUNC(e->devid),
+                                   e->flags, e->ext);
+
                        devid = e->devid;
                        set_dev_entry_from_acpi(iommu, devid, e->flags,
                                                e->ext);
                        break;
                case IVHD_DEV_EXT_SELECT_RANGE:
+
+                       DUMP_printk("  DEV_EXT_SELECT_RANGE\t devid: "
+                                   "%02x:%02x.%x flags: %02x ext: %08x\n",
+                                   PCI_BUS(e->devid),
+                                   PCI_SLOT(e->devid),
+                                   PCI_FUNC(e->devid),
+                                   e->flags, e->ext);
+
                        devid_start = e->devid;
                        flags = e->flags;
                        ext_flags = e->ext;
                        alias = false;
                        break;
                case IVHD_DEV_RANGE_END:
+
+                       DUMP_printk("  DEV_RANGE_END\t\t devid: %02x:%02x.%x\n",
+                                   PCI_BUS(e->devid),
+                                   PCI_SLOT(e->devid),
+                                   PCI_FUNC(e->devid));
+
                        devid = e->devid;
                        for (dev_i = devid_start; dev_i <= devid; ++dev_i) {
                                if (alias)
@@ -679,7 +774,7 @@ static void __init free_iommu_all(void)
 {
        struct amd_iommu *iommu, *next;
 
-       list_for_each_entry_safe(iommu, next, &amd_iommu_list, list) {
+       for_each_iommu_safe(iommu, next) {
                list_del(&iommu->list);
                free_iommu_one(iommu);
                kfree(iommu);
@@ -710,7 +805,6 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
        if (!iommu->mmio_base)
                return -ENOMEM;
 
-       iommu_set_device_table(iommu);
        iommu->cmd_buf = alloc_command_buffer(iommu);
        if (!iommu->cmd_buf)
                return -ENOMEM;
@@ -746,6 +840,15 @@ static int __init init_iommu_all(struct acpi_table_header *table)
                h = (struct ivhd_header *)p;
                switch (*p) {
                case ACPI_IVHD_TYPE:
+
+                       DUMP_printk("IOMMU: device: %02x:%02x.%01x cap: %04x "
+                                   "seg: %d flags: %01x info %04x\n",
+                                   PCI_BUS(h->devid), PCI_SLOT(h->devid),
+                                   PCI_FUNC(h->devid), h->cap_ptr,
+                                   h->pci_seg, h->flags, h->info);
+                       DUMP_printk("       mmio-addr: %016llx\n",
+                                   h->mmio_phys);
+
                        iommu = kzalloc(sizeof(struct amd_iommu), GFP_KERNEL);
                        if (iommu == NULL)
                                return -ENOMEM;
@@ -773,56 +876,9 @@ static int __init init_iommu_all(struct acpi_table_header *table)
  *
  ****************************************************************************/
 
-static int __init iommu_setup_msix(struct amd_iommu *iommu)
-{
-       struct amd_iommu *curr;
-       struct msix_entry entries[32]; /* only 32 supported by AMD IOMMU */
-       int nvec = 0, i;
-
-       list_for_each_entry(curr, &amd_iommu_list, list) {
-               if (curr->dev == iommu->dev) {
-                       entries[nvec].entry = curr->evt_msi_num;
-                       entries[nvec].vector = 0;
-                       curr->int_enabled = true;
-                       nvec++;
-               }
-       }
-
-       if (pci_enable_msix(iommu->dev, entries, nvec)) {
-               pci_disable_msix(iommu->dev);
-               return 1;
-       }
-
-       for (i = 0; i < nvec; ++i) {
-               int r = request_irq(entries->vector, amd_iommu_int_handler,
-                                   IRQF_SAMPLE_RANDOM,
-                                   "AMD IOMMU",
-                                   NULL);
-               if (r)
-                       goto out_free;
-       }
-
-       return 0;
-
-out_free:
-       for (i -= 1; i >= 0; --i)
-               free_irq(entries->vector, NULL);
-
-       pci_disable_msix(iommu->dev);
-
-       return 1;
-}
-
 static int __init iommu_setup_msi(struct amd_iommu *iommu)
 {
        int r;
-       struct amd_iommu *curr;
-
-       list_for_each_entry(curr, &amd_iommu_list, list) {
-               if (curr->dev == iommu->dev)
-                       curr->int_enabled = true;
-       }
-
 
        if (pci_enable_msi(iommu->dev))
                return 1;
@@ -837,17 +893,18 @@ static int __init iommu_setup_msi(struct amd_iommu *iommu)
                return 1;
        }
 
+       iommu->int_enabled = true;
+       iommu_feature_enable(iommu, CONTROL_EVT_INT_EN);
+
        return 0;
 }
 
-static int __init iommu_init_msi(struct amd_iommu *iommu)
+static int iommu_init_msi(struct amd_iommu *iommu)
 {
        if (iommu->int_enabled)
                return 0;
 
-       if (pci_find_capability(iommu->dev, PCI_CAP_ID_MSIX))
-               return iommu_setup_msix(iommu);
-       else if (pci_find_capability(iommu->dev, PCI_CAP_ID_MSI))
+       if (pci_find_capability(iommu->dev, PCI_CAP_ID_MSI))
                return iommu_setup_msi(iommu);
 
        return 1;
@@ -899,6 +956,7 @@ static int __init init_exclusion_range(struct ivmd_header *m)
 static int __init init_unity_map_range(struct ivmd_header *m)
 {
        struct unity_map_entry *e = 0;
+       char *s;
 
        e = kzalloc(sizeof(*e), GFP_KERNEL);
        if (e == NULL)
@@ -906,14 +964,19 @@ static int __init init_unity_map_range(struct ivmd_header *m)
 
        switch (m->type) {
        default:
+               kfree(e);
+               return 0;
        case ACPI_IVMD_TYPE:
+               s = "IVMD_TYPEi\t\t\t";
                e->devid_start = e->devid_end = m->devid;
                break;
        case ACPI_IVMD_TYPE_ALL:
+               s = "IVMD_TYPE_ALL\t\t";
                e->devid_start = 0;
                e->devid_end = amd_iommu_last_bdf;
                break;
        case ACPI_IVMD_TYPE_RANGE:
+               s = "IVMD_TYPE_RANGE\t\t";
                e->devid_start = m->devid;
                e->devid_end = m->aux;
                break;
@@ -922,6 +985,13 @@ static int __init init_unity_map_range(struct ivmd_header *m)
        e->address_end = e->address_start + PAGE_ALIGN(m->range_length);
        e->prot = m->flags >> 1;
 
+       DUMP_printk("%s devid_start: %02x:%02x.%x devid_end: %02x:%02x.%x"
+                   " range_start: %016llx range_end: %016llx flags: %x\n", s,
+                   PCI_BUS(e->devid_start), PCI_SLOT(e->devid_start),
+                   PCI_FUNC(e->devid_start), PCI_BUS(e->devid_end),
+                   PCI_SLOT(e->devid_end), PCI_FUNC(e->devid_end),
+                   e->address_start, e->address_end, m->flags);
+
        list_add_tail(&e->list, &amd_iommu_unity_map);
 
        return 0;
@@ -967,18 +1037,28 @@ static void init_device_table(void)
  * This function finally enables all IOMMUs found in the system after
  * they have been initialized
  */
-static void __init enable_iommus(void)
+static void enable_iommus(void)
 {
        struct amd_iommu *iommu;
 
-       list_for_each_entry(iommu, &amd_iommu_list, list) {
+       for_each_iommu(iommu) {
+               iommu_set_device_table(iommu);
+               iommu_enable_command_buffer(iommu);
+               iommu_enable_event_buffer(iommu);
                iommu_set_exclusion_range(iommu);
                iommu_init_msi(iommu);
-               iommu_enable_event_logging(iommu);
                iommu_enable(iommu);
        }
 }
 
+static void disable_iommus(void)
+{
+       struct amd_iommu *iommu;
+
+       for_each_iommu(iommu)
+               iommu_disable(iommu);
+}
+
 /*
  * Suspend/Resume support
  * disable suspend until real resume implemented
@@ -986,12 +1066,31 @@ static void __init enable_iommus(void)
 
 static int amd_iommu_resume(struct sys_device *dev)
 {
+       /*
+        * Disable IOMMUs before reprogramming the hardware registers.
+        * IOMMU is still enabled from the resume kernel.
+        */
+       disable_iommus();
+
+       /* re-load the hardware */
+       enable_iommus();
+
+       /*
+        * we have to flush after the IOMMUs are enabled because a
+        * disabled IOMMU will never execute the commands we send
+        */
+       amd_iommu_flush_all_domains();
+       amd_iommu_flush_all_devices();
+
        return 0;
 }
 
 static int amd_iommu_suspend(struct sys_device *dev, pm_message_t state)
 {
-       return -EINVAL;
+       /* disable IOMMUs to go out of the way for BIOS */
+       disable_iommus();
+
+       return 0;
 }
 
 static struct sysdev_class amd_iommu_sysdev_class = {
@@ -1137,9 +1236,6 @@ int __init amd_iommu_init(void)
 
        enable_iommus();
 
-       printk(KERN_INFO "AMD IOMMU: aperture size is %d MB\n",
-                       (1 << (amd_iommu_aperture_order-20)));
-
        printk(KERN_INFO "AMD IOMMU: device isolation ");
        if (amd_iommu_isolate)
                printk("enabled\n");
@@ -1211,6 +1307,13 @@ void __init amd_iommu_detect(void)
  *
  ****************************************************************************/
 
+static int __init parse_amd_iommu_dump(char *str)
+{
+       amd_iommu_dump = true;
+
+       return 1;
+}
+
 static int __init parse_amd_iommu_options(char *str)
 {
        for (; *str; ++str) {
@@ -1225,15 +1328,5 @@ static int __init parse_amd_iommu_options(char *str)
        return 1;
 }
 
-static int __init parse_amd_iommu_size_options(char *str)
-{
-       unsigned order = PAGE_SHIFT + get_order(memparse(str, &str));
-
-       if ((order > 24) && (order < 31))
-               amd_iommu_aperture_order = order;
-
-       return 1;
-}
-
+__setup("amd_iommu_dump", parse_amd_iommu_dump);
 __setup("amd_iommu=", parse_amd_iommu_options);
-__setup("amd_iommu_size=", parse_amd_iommu_size_options);
index f2870920f246a9f1d7e2075c37b65b05de27dbf1..a4c9cf0bf70bfdef62c638ed10d64c2a33a0a74b 100644 (file)
@@ -98,6 +98,29 @@ early_param("lapic", parse_lapic);
 /* Local APIC was disabled by the BIOS and enabled by the kernel */
 static int enabled_via_apicbase;
 
+/*
+ * Handle interrupt mode configuration register (IMCR).
+ * This register controls whether the interrupt signals
+ * that reach the BSP come from the master PIC or from the
+ * local APIC. Before entering Symmetric I/O Mode, either
+ * the BIOS or the operating system must switch out of
+ * PIC Mode by changing the IMCR.
+ */
+static inline void imcr_pic_to_apic(void)
+{
+       /* select IMCR register */
+       outb(0x70, 0x22);
+       /* NMI and 8259 INTR go through APIC */
+       outb(0x01, 0x23);
+}
+
+static inline void imcr_apic_to_pic(void)
+{
+       /* select IMCR register */
+       outb(0x70, 0x22);
+       /* NMI and 8259 INTR go directly to BSP */
+       outb(0x00, 0x23);
+}
 #endif
 
 #ifdef CONFIG_X86_64
@@ -111,13 +134,19 @@ static __init int setup_apicpmtimer(char *s)
 __setup("apicpmtimer", setup_apicpmtimer);
 #endif
 
+int x2apic_mode;
 #ifdef CONFIG_X86_X2APIC
-int x2apic;
 /* x2apic enabled before OS handover */
 static int x2apic_preenabled;
 static int disable_x2apic;
 static __init int setup_nox2apic(char *str)
 {
+       if (x2apic_enabled()) {
+               pr_warning("Bios already enabled x2apic, "
+                          "can't enforce nox2apic");
+               return 0;
+       }
+
        disable_x2apic = 1;
        setup_clear_cpu_cap(X86_FEATURE_X2APIC);
        return 0;
@@ -209,6 +238,31 @@ static int modern_apic(void)
        return lapic_get_version() >= 0x14;
 }
 
+/*
+ * bare function to substitute write operation
+ * and it's _that_ fast :)
+ */
+static void native_apic_write_dummy(u32 reg, u32 v)
+{
+       WARN_ON_ONCE((cpu_has_apic || !disable_apic));
+}
+
+static u32 native_apic_read_dummy(u32 reg)
+{
+       WARN_ON_ONCE((cpu_has_apic && !disable_apic));
+       return 0;
+}
+
+/*
+ * right after this call apic->write/read doesn't do anything
+ * note that there is no restore operation it works one way
+ */
+void apic_disable(void)
+{
+       apic->read = native_apic_read_dummy;
+       apic->write = native_apic_write_dummy;
+}
+
 void native_apic_wait_icr_idle(void)
 {
        while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
@@ -348,7 +402,7 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
 
 static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask)
 {
-       unsigned long reg = (lvt_off << 4) + APIC_EILVT0;
+       unsigned long reg = (lvt_off << 4) + APIC_EILVTn(0);
        unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
 
        apic_write(reg, v);
@@ -815,7 +869,7 @@ void clear_local_APIC(void)
        u32 v;
 
        /* APIC hasn't been mapped yet */
-       if (!x2apic && !apic_phys)
+       if (!x2apic_mode && !apic_phys)
                return;
 
        maxlvt = lapic_get_maxlvt();
@@ -1287,7 +1341,7 @@ void check_x2apic(void)
 {
        if (x2apic_enabled()) {
                pr_info("x2apic enabled by BIOS, switching to x2apic ops\n");
-               x2apic_preenabled = x2apic = 1;
+               x2apic_preenabled = x2apic_mode = 1;
        }
 }
 
@@ -1295,7 +1349,7 @@ void enable_x2apic(void)
 {
        int msr, msr2;
 
-       if (!x2apic)
+       if (!x2apic_mode)
                return;
 
        rdmsr(MSR_IA32_APICBASE, msr, msr2);
@@ -1304,6 +1358,7 @@ void enable_x2apic(void)
                wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0);
        }
 }
+#endif /* CONFIG_X86_X2APIC */
 
 void __init enable_IR_x2apic(void)
 {
@@ -1312,32 +1367,21 @@ void __init enable_IR_x2apic(void)
        unsigned long flags;
        struct IO_APIC_route_entry **ioapic_entries = NULL;
 
-       if (!cpu_has_x2apic)
-               return;
-
-       if (!x2apic_preenabled && disable_x2apic) {
-               pr_info("Skipped enabling x2apic and Interrupt-remapping "
-                       "because of nox2apic\n");
-               return;
+       ret = dmar_table_init();
+       if (ret) {
+               pr_debug("dmar_table_init() failed with %d:\n", ret);
+               goto ir_failed;
        }
 
-       if (x2apic_preenabled && disable_x2apic)
-               panic("Bios already enabled x2apic, can't enforce nox2apic");
-
-       if (!x2apic_preenabled && skip_ioapic_setup) {
-               pr_info("Skipped enabling x2apic and Interrupt-remapping "
-                       "because of skipping io-apic setup\n");
-               return;
+       if (!intr_remapping_supported()) {
+               pr_debug("intr-remapping not supported\n");
+               goto ir_failed;
        }
 
-       ret = dmar_table_init();
-       if (ret) {
-               pr_info("dmar_table_init() failed with %d:\n", ret);
 
-               if (x2apic_preenabled)
-                       panic("x2apic enabled by bios. But IR enabling failed");
-               else
-                       pr_info("Not enabling x2apic,Intr-remapping\n");
+       if (!x2apic_preenabled && skip_ioapic_setup) {
+               pr_info("Skipped enabling intr-remap because of skipping "
+                       "io-apic setup\n");
                return;
        }
 
@@ -1357,19 +1401,16 @@ void __init enable_IR_x2apic(void)
        mask_IO_APIC_setup(ioapic_entries);
        mask_8259A();
 
-       ret = enable_intr_remapping(EIM_32BIT_APIC_ID);
-
-       if (ret && x2apic_preenabled) {
-               local_irq_restore(flags);
-               panic("x2apic enabled by bios. But IR enabling failed");
-       }
-
+       ret = enable_intr_remapping(x2apic_supported());
        if (ret)
                goto end_restore;
 
-       if (!x2apic) {
-               x2apic = 1;
+       pr_info("Enabled Interrupt-remapping\n");
+
+       if (x2apic_supported() && !x2apic_mode) {
+               x2apic_mode = 1;
                enable_x2apic();
+               pr_info("Enabled x2apic\n");
        }
 
 end_restore:
@@ -1378,37 +1419,34 @@ end_restore:
                 * IR enabling failed
                 */
                restore_IO_APIC_setup(ioapic_entries);
-       else
-               reinit_intr_remapped_IO_APIC(x2apic_preenabled, ioapic_entries);
 
        unmask_8259A();
        local_irq_restore(flags);
 
 end:
-       if (!ret) {
-               if (!x2apic_preenabled)
-                       pr_info("Enabled x2apic and interrupt-remapping\n");
-               else
-                       pr_info("Enabled Interrupt-remapping\n");
-       } else
-               pr_err("Failed to enable Interrupt-remapping and x2apic\n");
        if (ioapic_entries)
                free_ioapic_entries(ioapic_entries);
+
+       if (!ret)
+               return;
+
+ir_failed:
+       if (x2apic_preenabled)
+               panic("x2apic enabled by bios. But IR enabling failed");
+       else if (cpu_has_x2apic)
+               pr_info("Not enabling x2apic,Intr-remapping\n");
 #else
        if (!cpu_has_x2apic)
                return;
 
        if (x2apic_preenabled)
                panic("x2apic enabled prior OS handover,"
-                     " enable CONFIG_INTR_REMAP");
-
-       pr_info("Enable CONFIG_INTR_REMAP for enabling intr-remapping "
-               " and x2apic\n");
+                     " enable CONFIG_X86_X2APIC, CONFIG_INTR_REMAP");
 #endif
 
        return;
 }
-#endif /* CONFIG_X86_X2APIC */
+
 
 #ifdef CONFIG_X86_64
 /*
@@ -1425,7 +1463,6 @@ static int __init detect_init_APIC(void)
        }
 
        mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
-       boot_cpu_physical_apicid = 0;
        return 0;
 }
 #else
@@ -1539,32 +1576,49 @@ void __init early_init_lapic_mapping(void)
  */
 void __init init_apic_mappings(void)
 {
-       if (x2apic) {
+       unsigned int new_apicid;
+
+       if (x2apic_mode) {
                boot_cpu_physical_apicid = read_apic_id();
                return;
        }
 
-       /*
-        * If no local APIC can be found then set up a fake all
-        * zeroes page to simulate the local APIC and another
-        * one for the IO-APIC.
-        */
+       /* If no local APIC can be found return early */
        if (!smp_found_config && detect_init_APIC()) {
-               apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
-               apic_phys = __pa(apic_phys);
-       } else
+               /* lets NOP'ify apic operations */
+               pr_info("APIC: disable apic facility\n");
+               apic_disable();
+       } else {
                apic_phys = mp_lapic_addr;
 
-       set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
-       apic_printk(APIC_VERBOSE, "mapped APIC to %08lx (%08lx)\n",
-                               APIC_BASE, apic_phys);
+               /*
+                * acpi lapic path already maps that address in
+                * acpi_register_lapic_address()
+                */
+               if (!acpi_lapic)
+                       set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
+
+               apic_printk(APIC_VERBOSE, "mapped APIC to %08lx (%08lx)\n",
+                                       APIC_BASE, apic_phys);
+       }
 
        /*
         * Fetch the APIC ID of the BSP in case we have a
         * default configuration (or the MP table is broken).
         */
-       if (boot_cpu_physical_apicid == -1U)
-               boot_cpu_physical_apicid = read_apic_id();
+       new_apicid = read_apic_id();
+       if (boot_cpu_physical_apicid != new_apicid) {
+               boot_cpu_physical_apicid = new_apicid;
+               /*
+                * yeah -- we lie about apic_version
+                * in case if apic was disabled via boot option
+                * but it's not a problem for SMP compiled kernel
+                * since smp_sanity_check is prepared for such a case
+                * and disable smp mode
+                */
+               apic_version[new_apicid] =
+                        GET_APIC_VERSION(apic_read(APIC_LVR));
+       }
 }
 
 /*
@@ -1733,8 +1787,7 @@ void __init connect_bsp_APIC(void)
                 */
                apic_printk(APIC_VERBOSE, "leaving PIC mode, "
                                "enabling APIC mode.\n");
-               outb(0x70, 0x22);
-               outb(0x01, 0x23);
+               imcr_pic_to_apic();
        }
 #endif
        if (apic->enable_apic_mode)
@@ -1762,8 +1815,7 @@ void disconnect_bsp_APIC(int virt_wire_setup)
                 */
                apic_printk(APIC_VERBOSE, "disabling APIC mode, "
                                "entering PIC mode.\n");
-               outb(0x70, 0x22);
-               outb(0x00, 0x23);
+               imcr_apic_to_pic();
                return;
        }
 #endif
@@ -1969,10 +2021,10 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
 
        local_irq_save(flags);
        disable_local_APIC();
-#ifdef CONFIG_INTR_REMAP
+
        if (intr_remapping_enabled)
                disable_intr_remapping();
-#endif
+
        local_irq_restore(flags);
        return 0;
 }
@@ -1982,42 +2034,34 @@ static int lapic_resume(struct sys_device *dev)
        unsigned int l, h;
        unsigned long flags;
        int maxlvt;
-
-#ifdef CONFIG_INTR_REMAP
-       int ret;
+       int ret = 0;
        struct IO_APIC_route_entry **ioapic_entries = NULL;
 
        if (!apic_pm_state.active)
                return 0;
 
        local_irq_save(flags);
-       if (x2apic) {
+       if (intr_remapping_enabled) {
                ioapic_entries = alloc_ioapic_entries();
                if (!ioapic_entries) {
                        WARN(1, "Alloc ioapic_entries in lapic resume failed.");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto restore;
                }
 
                ret = save_IO_APIC_setup(ioapic_entries);
                if (ret) {
                        WARN(1, "Saving IO-APIC state failed: %d\n", ret);
                        free_ioapic_entries(ioapic_entries);
-                       return ret;
+                       goto restore;
                }
 
                mask_IO_APIC_setup(ioapic_entries);
                mask_8259A();
-               enable_x2apic();
        }
-#else
-       if (!apic_pm_state.active)
-               return 0;
 
-       local_irq_save(flags);
-       if (x2apic)
+       if (x2apic_mode)
                enable_x2apic();
-#endif
-
        else {
                /*
                 * Make sure the APICBASE points to the right address
@@ -2055,21 +2099,16 @@ static int lapic_resume(struct sys_device *dev)
        apic_write(APIC_ESR, 0);
        apic_read(APIC_ESR);
 
-#ifdef CONFIG_INTR_REMAP
-       if (intr_remapping_enabled)
-               reenable_intr_remapping(EIM_32BIT_APIC_ID);
-
-       if (x2apic) {
+       if (intr_remapping_enabled) {
+               reenable_intr_remapping(x2apic_mode);
                unmask_8259A();
                restore_IO_APIC_setup(ioapic_entries);
                free_ioapic_entries(ioapic_entries);
        }
-#endif
-
+restore:
        local_irq_restore(flags);
 
-
-       return 0;
+       return ret;
 }
 
 /*
@@ -2117,31 +2156,14 @@ static void apic_pm_activate(void) { }
 #endif /* CONFIG_PM */
 
 #ifdef CONFIG_X86_64
-/*
- * apic_is_clustered_box() -- Check if we can expect good TSC
- *
- * Thus far, the major user of this is IBM's Summit2 series:
- *
- * Clustered boxes may have unsynced TSC problems if they are
- * multi-chassis. Use available data to take a good guess.
- * If in doubt, go HPET.
- */
-__cpuinit int apic_is_clustered_box(void)
+
+static int __cpuinit apic_cluster_num(void)
 {
        int i, clusters, zeros;
        unsigned id;
        u16 *bios_cpu_apicid;
        DECLARE_BITMAP(clustermap, NUM_APIC_CLUSTERS);
 
-       /*
-        * there is not this kind of box with AMD CPU yet.
-        * Some AMD box with quadcore cpu and 8 sockets apicid
-        * will be [4, 0x23] or [8, 0x27] could be thought to
-        * vsmp box still need checking...
-        */
-       if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && !is_vsmp_box())
-               return 0;
-
        bios_cpu_apicid = early_per_cpu_ptr(x86_bios_cpu_apicid);
        bitmap_zero(clustermap, NUM_APIC_CLUSTERS);
 
@@ -2177,18 +2199,67 @@ __cpuinit int apic_is_clustered_box(void)
                        ++zeros;
        }
 
-       /* ScaleMP vSMPowered boxes have one cluster per board and TSCs are
-        * not guaranteed to be synced between boards
-        */
-       if (is_vsmp_box() && clusters > 1)
+       return clusters;
+}
+
+static int __cpuinitdata multi_checked;
+static int __cpuinitdata multi;
+
+static int __cpuinit set_multi(const struct dmi_system_id *d)
+{
+       if (multi)
+               return 0;
+       pr_info("APIC: %s detected, Multi Chassis\n", d->ident);
+       multi = 1;
+       return 0;
+}
+
+static const __cpuinitconst struct dmi_system_id multi_dmi_table[] = {
+       {
+               .callback = set_multi,
+               .ident = "IBM System Summit2",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Summit2"),
+               },
+       },
+       {}
+};
+
+static void __cpuinit dmi_check_multi(void)
+{
+       if (multi_checked)
+               return;
+
+       dmi_check_system(multi_dmi_table);
+       multi_checked = 1;
+}
+
+/*
+ * apic_is_clustered_box() -- Check if we can expect good TSC
+ *
+ * Thus far, the major user of this is IBM's Summit2 series:
+ * Clustered boxes may have unsynced TSC problems if they are
+ * multi-chassis.
+ * Use DMI to check them
+ */
+__cpuinit int apic_is_clustered_box(void)
+{
+       dmi_check_multi();
+       if (multi)
                return 1;
 
+       if (!is_vsmp_box())
+               return 0;
+
        /*
-        * If clusters > 2, then should be multi-chassis.
-        * May have to revisit this when multi-core + hyperthreaded CPUs come
-        * out, but AFAIK this will work even for them.
+        * ScaleMP vSMPowered boxes have one cluster per board and TSCs are
+        * not guaranteed to be synced between boards
         */
-       return (clusters > 2);
+       if (apic_cluster_num() > 1)
+               return 1;
+
+       return 0;
 }
 #endif
 
index 306e5e88fb6f4abc9a53a3ce8638ac904a67067e..d0c99abc26c32a8f0df48d61485b1f36acb9b4b2 100644 (file)
@@ -161,7 +161,7 @@ static int flat_apic_id_registered(void)
 
 static int flat_phys_pkg_id(int initial_apic_id, int index_msb)
 {
-       return hard_smp_processor_id() >> index_msb;
+       return initial_apic_id >> index_msb;
 }
 
 struct apic apic_flat =  {
@@ -235,7 +235,7 @@ static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
         * regardless of how many processors are present (x86_64 ES7000
         * is an example).
         */
-       if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID &&
+       if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
                (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
                printk(KERN_DEBUG "system APIC only can use physical flat");
                return 1;
index 302947775575ebb69a670a4ef10f0184b2b82ac9..69328ac8de9c86e106d30af1337a80ab0d4488b1 100644 (file)
@@ -145,7 +145,7 @@ es7000_rename_gsi(int ioapic, int gsi)
        return gsi;
 }
 
-static int wakeup_secondary_cpu_via_mip(int cpu, unsigned long eip)
+static int __cpuinit wakeup_secondary_cpu_via_mip(int cpu, unsigned long eip)
 {
        unsigned long vect = 0, psaival = 0;
 
index 30da617d18e4735de234904fdc005cf527930c89..1946fac42ab3cb8a406d46509a983163cd347008 100644 (file)
@@ -59,6 +59,7 @@
 #include <asm/setup.h>
 #include <asm/irq_remapping.h>
 #include <asm/hpet.h>
+#include <asm/hw_irq.h>
 #include <asm/uv/uv_hub.h>
 #include <asm/uv/uv_irq.h>
 
@@ -129,12 +130,9 @@ struct irq_pin_list {
        struct irq_pin_list *next;
 };
 
-static struct irq_pin_list *get_one_free_irq_2_pin(int cpu)
+static struct irq_pin_list *get_one_free_irq_2_pin(int node)
 {
        struct irq_pin_list *pin;
-       int node;
-
-       node = cpu_to_node(cpu);
 
        pin = kzalloc_node(sizeof(*pin), GFP_ATOMIC, node);
 
@@ -148,9 +146,6 @@ struct irq_cfg {
        unsigned move_cleanup_count;
        u8 vector;
        u8 move_in_progress : 1;
-#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
-       u8 move_desc_pending : 1;
-#endif
 };
 
 /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
@@ -212,12 +207,9 @@ static struct irq_cfg *irq_cfg(unsigned int irq)
        return cfg;
 }
 
-static struct irq_cfg *get_one_free_irq_cfg(int cpu)
+static struct irq_cfg *get_one_free_irq_cfg(int node)
 {
        struct irq_cfg *cfg;
-       int node;
-
-       node = cpu_to_node(cpu);
 
        cfg = kzalloc_node(sizeof(*cfg), GFP_ATOMIC, node);
        if (cfg) {
@@ -238,13 +230,13 @@ static struct irq_cfg *get_one_free_irq_cfg(int cpu)
        return cfg;
 }
 
-int arch_init_chip_data(struct irq_desc *desc, int cpu)
+int arch_init_chip_data(struct irq_desc *desc, int node)
 {
        struct irq_cfg *cfg;
 
        cfg = desc->chip_data;
        if (!cfg) {
-               desc->chip_data = get_one_free_irq_cfg(cpu);
+               desc->chip_data = get_one_free_irq_cfg(node);
                if (!desc->chip_data) {
                        printk(KERN_ERR "can not alloc irq_cfg\n");
                        BUG_ON(1);
@@ -254,10 +246,9 @@ int arch_init_chip_data(struct irq_desc *desc, int cpu)
        return 0;
 }
 
-#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
-
+/* for move_irq_desc */
 static void
-init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int cpu)
+init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int node)
 {
        struct irq_pin_list *old_entry, *head, *tail, *entry;
 
@@ -266,7 +257,7 @@ init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int cpu)
        if (!old_entry)
                return;
 
-       entry = get_one_free_irq_2_pin(cpu);
+       entry = get_one_free_irq_2_pin(node);
        if (!entry)
                return;
 
@@ -276,7 +267,7 @@ init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int cpu)
        tail            = entry;
        old_entry       = old_entry->next;
        while (old_entry) {
-               entry = get_one_free_irq_2_pin(cpu);
+               entry = get_one_free_irq_2_pin(node);
                if (!entry) {
                        entry = head;
                        while (entry) {
@@ -316,12 +307,12 @@ static void free_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg)
 }
 
 void arch_init_copy_chip_data(struct irq_desc *old_desc,
-                                struct irq_desc *desc, int cpu)
+                                struct irq_desc *desc, int node)
 {
        struct irq_cfg *cfg;
        struct irq_cfg *old_cfg;
 
-       cfg = get_one_free_irq_cfg(cpu);
+       cfg = get_one_free_irq_cfg(node);
 
        if (!cfg)
                return;
@@ -332,7 +323,7 @@ void arch_init_copy_chip_data(struct irq_desc *old_desc,
 
        memcpy(cfg, old_cfg, sizeof(struct irq_cfg));
 
-       init_copy_irq_2_pin(old_cfg, cfg, cpu);
+       init_copy_irq_2_pin(old_cfg, cfg, node);
 }
 
 static void free_irq_cfg(struct irq_cfg *old_cfg)
@@ -356,19 +347,7 @@ void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc)
                old_desc->chip_data = NULL;
        }
 }
-
-static void
-set_extra_move_desc(struct irq_desc *desc, const struct cpumask *mask)
-{
-       struct irq_cfg *cfg = desc->chip_data;
-
-       if (!cfg->move_in_progress) {
-               /* it means that domain is not changed */
-               if (!cpumask_intersects(desc->affinity, mask))
-                       cfg->move_desc_pending = 1;
-       }
-}
-#endif
+/* end for move_irq_desc */
 
 #else
 static struct irq_cfg *irq_cfg(unsigned int irq)
@@ -378,13 +357,6 @@ static struct irq_cfg *irq_cfg(unsigned int irq)
 
 #endif
 
-#ifndef CONFIG_NUMA_MIGRATE_IRQ_DESC
-static inline void
-set_extra_move_desc(struct irq_desc *desc, const struct cpumask *mask)
-{
-}
-#endif
-
 struct io_apic {
        unsigned int index;
        unsigned int unused[3];
@@ -518,132 +490,18 @@ static void ioapic_mask_entry(int apic, int pin)
        spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-#ifdef CONFIG_SMP
-static void send_cleanup_vector(struct irq_cfg *cfg)
-{
-       cpumask_var_t cleanup_mask;
-
-       if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
-               unsigned int i;
-               cfg->move_cleanup_count = 0;
-               for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
-                       cfg->move_cleanup_count++;
-               for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
-                       apic->send_IPI_mask(cpumask_of(i), IRQ_MOVE_CLEANUP_VECTOR);
-       } else {
-               cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask);
-               cfg->move_cleanup_count = cpumask_weight(cleanup_mask);
-               apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
-               free_cpumask_var(cleanup_mask);
-       }
-       cfg->move_in_progress = 0;
-}
-
-static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
-{
-       int apic, pin;
-       struct irq_pin_list *entry;
-       u8 vector = cfg->vector;
-
-       entry = cfg->irq_2_pin;
-       for (;;) {
-               unsigned int reg;
-
-               if (!entry)
-                       break;
-
-               apic = entry->apic;
-               pin = entry->pin;
-               /*
-                * With interrupt-remapping, destination information comes
-                * from interrupt-remapping table entry.
-                */
-               if (!irq_remapped(irq))
-                       io_apic_write(apic, 0x11 + pin*2, dest);
-               reg = io_apic_read(apic, 0x10 + pin*2);
-               reg &= ~IO_APIC_REDIR_VECTOR_MASK;
-               reg |= vector;
-               io_apic_modify(apic, 0x10 + pin*2, reg);
-               if (!entry->next)
-                       break;
-               entry = entry->next;
-       }
-}
-
-static int
-assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask);
-
-/*
- * Either sets desc->affinity to a valid value, and returns
- * ->cpu_mask_to_apicid of that, or returns BAD_APICID and
- * leaves desc->affinity untouched.
- */
-static unsigned int
-set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask)
-{
-       struct irq_cfg *cfg;
-       unsigned int irq;
-
-       if (!cpumask_intersects(mask, cpu_online_mask))
-               return BAD_APICID;
-
-       irq = desc->irq;
-       cfg = desc->chip_data;
-       if (assign_irq_vector(irq, cfg, mask))
-               return BAD_APICID;
-
-       /* check that before desc->addinity get updated */
-       set_extra_move_desc(desc, mask);
-
-       cpumask_copy(desc->affinity, mask);
-
-       return apic->cpu_mask_to_apicid_and(desc->affinity, cfg->domain);
-}
-
-static void
-set_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
-{
-       struct irq_cfg *cfg;
-       unsigned long flags;
-       unsigned int dest;
-       unsigned int irq;
-
-       irq = desc->irq;
-       cfg = desc->chip_data;
-
-       spin_lock_irqsave(&ioapic_lock, flags);
-       dest = set_desc_affinity(desc, mask);
-       if (dest != BAD_APICID) {
-               /* Only the high 8 bits are valid. */
-               dest = SET_APIC_LOGICAL_ID(dest);
-               __target_IO_APIC_irq(irq, dest, cfg);
-       }
-       spin_unlock_irqrestore(&ioapic_lock, flags);
-}
-
-static void
-set_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask)
-{
-       struct irq_desc *desc;
-
-       desc = irq_to_desc(irq);
-
-       set_ioapic_affinity_irq_desc(desc, mask);
-}
-#endif /* CONFIG_SMP */
-
 /*
  * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
  * shared ISA-space IRQs, so we have to support them. We are super
  * fast in the common case, and fast for shared ISA-space IRQs.
  */
-static void add_pin_to_irq_cpu(struct irq_cfg *cfg, int cpu, int apic, int pin)
+static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
 {
        struct irq_pin_list *entry;
 
        entry = cfg->irq_2_pin;
        if (!entry) {
-               entry = get_one_free_irq_2_pin(cpu);
+               entry = get_one_free_irq_2_pin(node);
                if (!entry) {
                        printk(KERN_ERR "can not alloc irq_2_pin to add %d - %d\n",
                                        apic, pin);
@@ -663,7 +521,7 @@ static void add_pin_to_irq_cpu(struct irq_cfg *cfg, int cpu, int apic, int pin)
                entry = entry->next;
        }
 
-       entry->next = get_one_free_irq_2_pin(cpu);
+       entry->next = get_one_free_irq_2_pin(node);
        entry = entry->next;
        entry->apic = apic;
        entry->pin = pin;
@@ -672,7 +530,7 @@ static void add_pin_to_irq_cpu(struct irq_cfg *cfg, int cpu, int apic, int pin)
 /*
  * Reroute an IRQ to a different pin.
  */
-static void __init replace_pin_at_irq_cpu(struct irq_cfg *cfg, int cpu,
+static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node,
                                      int oldapic, int oldpin,
                                      int newapic, int newpin)
 {
@@ -692,7 +550,7 @@ static void __init replace_pin_at_irq_cpu(struct irq_cfg *cfg, int cpu,
 
        /* why? call replace before add? */
        if (!replaced)
-               add_pin_to_irq_cpu(cfg, cpu, newapic, newpin);
+               add_pin_to_irq_node(cfg, node, newapic, newpin);
 }
 
 static inline void io_apic_modify_irq(struct irq_cfg *cfg,
@@ -850,7 +708,6 @@ static int __init ioapic_pirq_setup(char *str)
 __setup("pirq=", ioapic_pirq_setup);
 #endif /* CONFIG_X86_32 */
 
-#ifdef CONFIG_INTR_REMAP
 struct IO_APIC_route_entry **alloc_ioapic_entries(void)
 {
        int apic;
@@ -948,20 +805,6 @@ int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
        return 0;
 }
 
-void reinit_intr_remapped_IO_APIC(int intr_remapping,
-       struct IO_APIC_route_entry **ioapic_entries)
-
-{
-       /*
-        * for now plain restore of previous settings.
-        * TBD: In the case of OS enabling interrupt-remapping,
-        * IO-APIC RTE's need to be setup to point to interrupt-remapping
-        * table entries. for now, do a plain restore, and wait for
-        * the setup_IO_APIC_irqs() to do proper initialization.
-        */
-       restore_IO_APIC_setup(ioapic_entries);
-}
-
 void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries)
 {
        int apic;
@@ -971,7 +814,6 @@ void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries)
 
        kfree(ioapic_entries);
 }
-#endif
 
 /*
  * Find the IRQ entry number of a certain pin.
@@ -1032,54 +874,6 @@ static int __init find_isa_irq_apic(int irq, int type)
        return -1;
 }
 
-/*
- * Find a specific PCI IRQ entry.
- * Not an __init, possibly needed by modules
- */
-static int pin_2_irq(int idx, int apic, int pin);
-
-int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
-{
-       int apic, i, best_guess = -1;
-
-       apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
-               bus, slot, pin);
-       if (test_bit(bus, mp_bus_not_pci)) {
-               apic_printk(APIC_VERBOSE, "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
-               return -1;
-       }
-       for (i = 0; i < mp_irq_entries; i++) {
-               int lbus = mp_irqs[i].srcbus;
-
-               for (apic = 0; apic < nr_ioapics; apic++)
-                       if (mp_ioapics[apic].apicid == mp_irqs[i].dstapic ||
-                           mp_irqs[i].dstapic == MP_APIC_ALL)
-                               break;
-
-               if (!test_bit(lbus, mp_bus_not_pci) &&
-                   !mp_irqs[i].irqtype &&
-                   (bus == lbus) &&
-                   (slot == ((mp_irqs[i].srcbusirq >> 2) & 0x1f))) {
-                       int irq = pin_2_irq(i, apic, mp_irqs[i].dstirq);
-
-                       if (!(apic || IO_APIC_IRQ(irq)))
-                               continue;
-
-                       if (pin == (mp_irqs[i].srcbusirq & 3))
-                               return irq;
-                       /*
-                        * Use the first all-but-pin matching entry as a
-                        * best-guess fuzzy result for broken mptables.
-                        */
-                       if (best_guess < 0)
-                               best_guess = irq;
-               }
-       }
-       return best_guess;
-}
-
-EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
-
 #if defined(CONFIG_EISA) || defined(CONFIG_MCA)
 /*
  * EISA Edge/Level control register, ELCR
@@ -1298,6 +1092,64 @@ static int pin_2_irq(int idx, int apic, int pin)
        return irq;
 }
 
+/*
+ * Find a specific PCI IRQ entry.
+ * Not an __init, possibly needed by modules
+ */
+int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin,
+                               struct io_apic_irq_attr *irq_attr)
+{
+       int apic, i, best_guess = -1;
+
+       apic_printk(APIC_DEBUG,
+                   "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
+                   bus, slot, pin);
+       if (test_bit(bus, mp_bus_not_pci)) {
+               apic_printk(APIC_VERBOSE,
+                           "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
+               return -1;
+       }
+       for (i = 0; i < mp_irq_entries; i++) {
+               int lbus = mp_irqs[i].srcbus;
+
+               for (apic = 0; apic < nr_ioapics; apic++)
+                       if (mp_ioapics[apic].apicid == mp_irqs[i].dstapic ||
+                           mp_irqs[i].dstapic == MP_APIC_ALL)
+                               break;
+
+               if (!test_bit(lbus, mp_bus_not_pci) &&
+                   !mp_irqs[i].irqtype &&
+                   (bus == lbus) &&
+                   (slot == ((mp_irqs[i].srcbusirq >> 2) & 0x1f))) {
+                       int irq = pin_2_irq(i, apic, mp_irqs[i].dstirq);
+
+                       if (!(apic || IO_APIC_IRQ(irq)))
+                               continue;
+
+                       if (pin == (mp_irqs[i].srcbusirq & 3)) {
+                               set_io_apic_irq_attr(irq_attr, apic,
+                                                    mp_irqs[i].dstirq,
+                                                    irq_trigger(i),
+                                                    irq_polarity(i));
+                               return irq;
+                       }
+                       /*
+                        * Use the first all-but-pin matching entry as a
+                        * best-guess fuzzy result for broken mptables.
+                        */
+                       if (best_guess < 0) {
+                               set_io_apic_irq_attr(irq_attr, apic,
+                                                    mp_irqs[i].dstirq,
+                                                    irq_trigger(i),
+                                                    irq_polarity(i));
+                               best_guess = irq;
+                       }
+               }
+       }
+       return best_guess;
+}
+EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
+
 void lock_vector_lock(void)
 {
        /* Used to the online set of cpus does not change
@@ -1628,58 +1480,70 @@ static void setup_IO_APIC_irq(int apic_id, int pin, unsigned int irq, struct irq
        ioapic_write_entry(apic_id, pin, entry);
 }
 
+static struct {
+       DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1);
+} mp_ioapic_routing[MAX_IO_APICS];
+
 static void __init setup_IO_APIC_irqs(void)
 {
-       int apic_id, pin, idx, irq;
+       int apic_id = 0, pin, idx, irq;
        int notcon = 0;
        struct irq_desc *desc;
        struct irq_cfg *cfg;
-       int cpu = boot_cpu_id;
+       int node = cpu_to_node(boot_cpu_id);
 
        apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
 
-       for (apic_id = 0; apic_id < nr_ioapics; apic_id++) {
-               for (pin = 0; pin < nr_ioapic_registers[apic_id]; pin++) {
-
-                       idx = find_irq_entry(apic_id, pin, mp_INT);
-                       if (idx == -1) {
-                               if (!notcon) {
-                                       notcon = 1;
-                                       apic_printk(APIC_VERBOSE,
-                                               KERN_DEBUG " %d-%d",
-                                               mp_ioapics[apic_id].apicid, pin);
-                               } else
-                                       apic_printk(APIC_VERBOSE, " %d-%d",
-                                               mp_ioapics[apic_id].apicid, pin);
-                               continue;
-                       }
-                       if (notcon) {
-                               apic_printk(APIC_VERBOSE,
-                                       " (apicid-pin) not connected\n");
-                               notcon = 0;
-                       }
+#ifdef CONFIG_ACPI
+       if (!acpi_disabled && acpi_ioapic) {
+               apic_id = mp_find_ioapic(0);
+               if (apic_id < 0)
+                       apic_id = 0;
+       }
+#endif
 
-                       irq = pin_2_irq(idx, apic_id, pin);
+       for (pin = 0; pin < nr_ioapic_registers[apic_id]; pin++) {
+               idx = find_irq_entry(apic_id, pin, mp_INT);
+               if (idx == -1) {
+                       if (!notcon) {
+                               notcon = 1;
+                               apic_printk(APIC_VERBOSE,
+                                       KERN_DEBUG " %d-%d",
+                                       mp_ioapics[apic_id].apicid, pin);
+                       } else
+                               apic_printk(APIC_VERBOSE, " %d-%d",
+                                       mp_ioapics[apic_id].apicid, pin);
+                       continue;
+               }
+               if (notcon) {
+                       apic_printk(APIC_VERBOSE,
+                               " (apicid-pin) not connected\n");
+                       notcon = 0;
+               }
 
-                       /*
-                        * Skip the timer IRQ if there's a quirk handler
-                        * installed and if it returns 1:
-                        */
-                       if (apic->multi_timer_check &&
-                                       apic->multi_timer_check(apic_id, irq))
-                               continue;
+               irq = pin_2_irq(idx, apic_id, pin);
 
-                       desc = irq_to_desc_alloc_cpu(irq, cpu);
-                       if (!desc) {
-                               printk(KERN_INFO "can not get irq_desc for %d\n", irq);
-                               continue;
-                       }
-                       cfg = desc->chip_data;
-                       add_pin_to_irq_cpu(cfg, cpu, apic_id, pin);
+               /*
+                * Skip the timer IRQ if there's a quirk handler
+                * installed and if it returns 1:
+                */
+               if (apic->multi_timer_check &&
+                               apic->multi_timer_check(apic_id, irq))
+                       continue;
 
-                       setup_IO_APIC_irq(apic_id, pin, irq, desc,
-                                       irq_trigger(idx), irq_polarity(idx));
+               desc = irq_to_desc_alloc_node(irq, node);
+               if (!desc) {
+                       printk(KERN_INFO "can not get irq_desc for %d\n", irq);
+                       continue;
                }
+               cfg = desc->chip_data;
+               add_pin_to_irq_node(cfg, node, apic_id, pin);
+               /*
+                * don't mark it in pin_programmed, so later acpi could
+                * set it correctly when irq < 16
+                */
+               setup_IO_APIC_irq(apic_id, pin, irq, desc,
+                               irq_trigger(idx), irq_polarity(idx));
        }
 
        if (notcon)
@@ -1869,7 +1733,7 @@ __apicdebuginit(void) print_APIC_bitfield(int base)
 
 __apicdebuginit(void) print_local_APIC(void *dummy)
 {
-       unsigned int v, ver, maxlvt;
+       unsigned int i, v, ver, maxlvt;
        u64 icr;
 
        if (apic_verbosity == APIC_QUIET)
@@ -1957,6 +1821,18 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
        printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v);
        v = apic_read(APIC_TDCR);
        printk(KERN_DEBUG "... APIC TDCR: %08x\n", v);
+
+       if (boot_cpu_has(X86_FEATURE_EXTAPIC)) {
+               v = apic_read(APIC_EFEAT);
+               maxlvt = (v >> 16) & 0xff;
+               printk(KERN_DEBUG "... APIC EFEAT: %08x\n", v);
+               v = apic_read(APIC_ECTRL);
+               printk(KERN_DEBUG "... APIC ECTRL: %08x\n", v);
+               for (i = 0; i < maxlvt; i++) {
+                       v = apic_read(APIC_EILVTn(i));
+                       printk(KERN_DEBUG "... APIC EILVT%d: %08x\n", i, v);
+               }
+       }
        printk("\n");
 }
 
@@ -2005,6 +1881,11 @@ __apicdebuginit(void) print_PIC(void)
 __apicdebuginit(int) print_all_ICs(void)
 {
        print_PIC();
+
+       /* don't print out if apic is not there */
+       if (!cpu_has_apic || disable_apic)
+               return 0;
+
        print_all_local_APICs();
        print_IO_APIC();
 
@@ -2360,9 +2241,121 @@ static int ioapic_retrigger_irq(unsigned int irq)
  */
 
 #ifdef CONFIG_SMP
+static void send_cleanup_vector(struct irq_cfg *cfg)
+{
+       cpumask_var_t cleanup_mask;
+
+       if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
+               unsigned int i;
+               cfg->move_cleanup_count = 0;
+               for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
+                       cfg->move_cleanup_count++;
+               for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
+                       apic->send_IPI_mask(cpumask_of(i), IRQ_MOVE_CLEANUP_VECTOR);
+       } else {
+               cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask);
+               cfg->move_cleanup_count = cpumask_weight(cleanup_mask);
+               apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
+               free_cpumask_var(cleanup_mask);
+       }
+       cfg->move_in_progress = 0;
+}
+
+static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
+{
+       int apic, pin;
+       struct irq_pin_list *entry;
+       u8 vector = cfg->vector;
+
+       entry = cfg->irq_2_pin;
+       for (;;) {
+               unsigned int reg;
+
+               if (!entry)
+                       break;
+
+               apic = entry->apic;
+               pin = entry->pin;
+               /*
+                * With interrupt-remapping, destination information comes
+                * from interrupt-remapping table entry.
+                */
+               if (!irq_remapped(irq))
+                       io_apic_write(apic, 0x11 + pin*2, dest);
+               reg = io_apic_read(apic, 0x10 + pin*2);
+               reg &= ~IO_APIC_REDIR_VECTOR_MASK;
+               reg |= vector;
+               io_apic_modify(apic, 0x10 + pin*2, reg);
+               if (!entry->next)
+                       break;
+               entry = entry->next;
+       }
+}
+
+static int
+assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask);
+
+/*
+ * Either sets desc->affinity to a valid value, and returns
+ * ->cpu_mask_to_apicid of that, or returns BAD_APICID and
+ * leaves desc->affinity untouched.
+ */
+static unsigned int
+set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask)
+{
+       struct irq_cfg *cfg;
+       unsigned int irq;
+
+       if (!cpumask_intersects(mask, cpu_online_mask))
+               return BAD_APICID;
+
+       irq = desc->irq;
+       cfg = desc->chip_data;
+       if (assign_irq_vector(irq, cfg, mask))
+               return BAD_APICID;
+
+       cpumask_copy(desc->affinity, mask);
+
+       return apic->cpu_mask_to_apicid_and(desc->affinity, cfg->domain);
+}
+
+static int
+set_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
+{
+       struct irq_cfg *cfg;
+       unsigned long flags;
+       unsigned int dest;
+       unsigned int irq;
+       int ret = -1;
+
+       irq = desc->irq;
+       cfg = desc->chip_data;
+
+       spin_lock_irqsave(&ioapic_lock, flags);
+       dest = set_desc_affinity(desc, mask);
+       if (dest != BAD_APICID) {
+               /* Only the high 8 bits are valid. */
+               dest = SET_APIC_LOGICAL_ID(dest);
+               __target_IO_APIC_irq(irq, dest, cfg);
+               ret = 0;
+       }
+       spin_unlock_irqrestore(&ioapic_lock, flags);
+
+       return ret;
+}
+
+static int
+set_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask)
+{
+       struct irq_desc *desc;
+
+       desc = irq_to_desc(irq);
+
+       return set_ioapic_affinity_irq_desc(desc, mask);
+}
+
+#ifdef CONFIG_INTR_REMAP
 
-#ifdef CONFIG_INTR_REMAP
-
 /*
  * Migrate the IO-APIC irq in the presence of intr-remapping.
  *
@@ -2374,26 +2367,25 @@ static int ioapic_retrigger_irq(unsigned int irq)
  * Real vector that is used for interrupting cpu will be coming from
  * the interrupt-remapping table entry.
  */
-static void
+static int
 migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
 {
        struct irq_cfg *cfg;
        struct irte irte;
        unsigned int dest;
        unsigned int irq;
+       int ret = -1;
 
        if (!cpumask_intersects(mask, cpu_online_mask))
-               return;
+               return ret;
 
        irq = desc->irq;
        if (get_irte(irq, &irte))
-               return;
+               return ret;
 
        cfg = desc->chip_data;
        if (assign_irq_vector(irq, cfg, mask))
-               return;
-
-       set_extra_move_desc(desc, mask);
+               return ret;
 
        dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask);
 
@@ -2409,27 +2401,30 @@ migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
                send_cleanup_vector(cfg);
 
        cpumask_copy(desc->affinity, mask);
+
+       return 0;
 }
 
 /*
  * Migrates the IRQ destination in the process context.
  */
-static void set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
+static int set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
                                            const struct cpumask *mask)
 {
-       migrate_ioapic_irq_desc(desc, mask);
+       return migrate_ioapic_irq_desc(desc, mask);
 }
-static void set_ir_ioapic_affinity_irq(unsigned int irq,
+static int set_ir_ioapic_affinity_irq(unsigned int irq,
                                       const struct cpumask *mask)
 {
        struct irq_desc *desc = irq_to_desc(irq);
 
-       set_ir_ioapic_affinity_irq_desc(desc, mask);
+       return set_ir_ioapic_affinity_irq_desc(desc, mask);
 }
 #else
-static inline void set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
+static inline int set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
                                                   const struct cpumask *mask)
 {
+       return 0;
 }
 #endif
 
@@ -2491,86 +2486,19 @@ static void irq_complete_move(struct irq_desc **descp)
        struct irq_cfg *cfg = desc->chip_data;
        unsigned vector, me;
 
-       if (likely(!cfg->move_in_progress)) {
-#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
-               if (likely(!cfg->move_desc_pending))
-                       return;
-
-               /* domain has not changed, but affinity did */
-               me = smp_processor_id();
-               if (cpumask_test_cpu(me, desc->affinity)) {
-                       *descp = desc = move_irq_desc(desc, me);
-                       /* get the new one */
-                       cfg = desc->chip_data;
-                       cfg->move_desc_pending = 0;
-               }
-#endif
+       if (likely(!cfg->move_in_progress))
                return;
-       }
 
        vector = ~get_irq_regs()->orig_ax;
        me = smp_processor_id();
 
-       if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain)) {
-#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
-               *descp = desc = move_irq_desc(desc, me);
-               /* get the new one */
-               cfg = desc->chip_data;
-#endif
+       if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
                send_cleanup_vector(cfg);
-       }
 }
 #else
 static inline void irq_complete_move(struct irq_desc **descp) {}
 #endif
 
-static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
-{
-       int apic, pin;
-       struct irq_pin_list *entry;
-
-       entry = cfg->irq_2_pin;
-       for (;;) {
-
-               if (!entry)
-                       break;
-
-               apic = entry->apic;
-               pin = entry->pin;
-               io_apic_eoi(apic, pin);
-               entry = entry->next;
-       }
-}
-
-static void
-eoi_ioapic_irq(struct irq_desc *desc)
-{
-       struct irq_cfg *cfg;
-       unsigned long flags;
-       unsigned int irq;
-
-       irq = desc->irq;
-       cfg = desc->chip_data;
-
-       spin_lock_irqsave(&ioapic_lock, flags);
-       __eoi_ioapic_irq(irq, cfg);
-       spin_unlock_irqrestore(&ioapic_lock, flags);
-}
-
-#ifdef CONFIG_X86_X2APIC
-static void ack_x2apic_level(unsigned int irq)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-       ack_x2APIC_irq();
-       eoi_ioapic_irq(desc);
-}
-
-static void ack_x2apic_edge(unsigned int irq)
-{
-       ack_x2APIC_irq();
-}
-#endif
-
 static void ack_apic_edge(unsigned int irq)
 {
        struct irq_desc *desc = irq_to_desc(irq);
@@ -2634,9 +2562,6 @@ static void ack_apic_level(unsigned int irq)
         */
        ack_APIC_irq();
 
-       if (irq_remapped(irq))
-               eoi_ioapic_irq(desc);
-
        /* Now we can move and renable the irq */
        if (unlikely(do_unmask_irq)) {
                /* Only migrate the irq if the ack has been received.
@@ -2683,22 +2608,50 @@ static void ack_apic_level(unsigned int irq)
 }
 
 #ifdef CONFIG_INTR_REMAP
+static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
+{
+       int apic, pin;
+       struct irq_pin_list *entry;
+
+       entry = cfg->irq_2_pin;
+       for (;;) {
+
+               if (!entry)
+                       break;
+
+               apic = entry->apic;
+               pin = entry->pin;
+               io_apic_eoi(apic, pin);
+               entry = entry->next;
+       }
+}
+
+static void
+eoi_ioapic_irq(struct irq_desc *desc)
+{
+       struct irq_cfg *cfg;
+       unsigned long flags;
+       unsigned int irq;
+
+       irq = desc->irq;
+       cfg = desc->chip_data;
+
+       spin_lock_irqsave(&ioapic_lock, flags);
+       __eoi_ioapic_irq(irq, cfg);
+       spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
 static void ir_ack_apic_edge(unsigned int irq)
 {
-#ifdef CONFIG_X86_X2APIC
-       if (x2apic_enabled())
-               return ack_x2apic_edge(irq);
-#endif
-       return ack_apic_edge(irq);
+       ack_APIC_irq();
 }
 
 static void ir_ack_apic_level(unsigned int irq)
 {
-#ifdef CONFIG_X86_X2APIC
-       if (x2apic_enabled())
-               return ack_x2apic_level(irq);
-#endif
-       return ack_apic_level(irq);
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       ack_APIC_irq();
+       eoi_ioapic_irq(desc);
 }
 #endif /* CONFIG_INTR_REMAP */
 
@@ -2903,7 +2856,7 @@ static inline void __init check_timer(void)
 {
        struct irq_desc *desc = irq_to_desc(0);
        struct irq_cfg *cfg = desc->chip_data;
-       int cpu = boot_cpu_id;
+       int node = cpu_to_node(boot_cpu_id);
        int apic1, pin1, apic2, pin2;
        unsigned long flags;
        int no_pin1 = 0;
@@ -2969,7 +2922,7 @@ static inline void __init check_timer(void)
                 * Ok, does IRQ0 through the IOAPIC work?
                 */
                if (no_pin1) {
-                       add_pin_to_irq_cpu(cfg, cpu, apic1, pin1);
+                       add_pin_to_irq_node(cfg, node, apic1, pin1);
                        setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
                } else {
                        /* for edge trigger, setup_IO_APIC_irq already
@@ -3006,7 +2959,7 @@ static inline void __init check_timer(void)
                /*
                 * legacy devices should be connected to IO APIC #0
                 */
-               replace_pin_at_irq_cpu(cfg, cpu, apic1, pin1, apic2, pin2);
+               replace_pin_at_irq_node(cfg, node, apic1, pin1, apic2, pin2);
                setup_timer_IRQ0_pin(apic2, pin2, cfg->vector);
                enable_8259A_irq(0);
                if (timer_irq_works()) {
@@ -3218,14 +3171,13 @@ static int nr_irqs_gsi = NR_IRQS_LEGACY;
 /*
  * Dynamic irq allocate and deallocation
  */
-unsigned int create_irq_nr(unsigned int irq_want)
+unsigned int create_irq_nr(unsigned int irq_want, int node)
 {
        /* Allocate an unused irq */
        unsigned int irq;
        unsigned int new;
        unsigned long flags;
        struct irq_cfg *cfg_new = NULL;
-       int cpu = boot_cpu_id;
        struct irq_desc *desc_new = NULL;
 
        irq = 0;
@@ -3234,7 +3186,7 @@ unsigned int create_irq_nr(unsigned int irq_want)
 
        spin_lock_irqsave(&vector_lock, flags);
        for (new = irq_want; new < nr_irqs; new++) {
-               desc_new = irq_to_desc_alloc_cpu(new, cpu);
+               desc_new = irq_to_desc_alloc_node(new, node);
                if (!desc_new) {
                        printk(KERN_INFO "can not get irq_desc for %d\n", new);
                        continue;
@@ -3243,6 +3195,9 @@ unsigned int create_irq_nr(unsigned int irq_want)
 
                if (cfg_new->vector != 0)
                        continue;
+
+               desc_new = move_irq_desc(desc_new, node);
+
                if (__assign_irq_vector(new, cfg_new, apic->target_cpus()) == 0)
                        irq = new;
                break;
@@ -3260,11 +3215,12 @@ unsigned int create_irq_nr(unsigned int irq_want)
 
 int create_irq(void)
 {
+       int node = cpu_to_node(boot_cpu_id);
        unsigned int irq_want;
        int irq;
 
        irq_want = nr_irqs_gsi;
-       irq = create_irq_nr(irq_want);
+       irq = create_irq_nr(irq_want, node);
 
        if (irq == 0)
                irq = -1;
@@ -3366,7 +3322,7 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
 }
 
 #ifdef CONFIG_SMP
-static void set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
+static int set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
 {
        struct irq_desc *desc = irq_to_desc(irq);
        struct irq_cfg *cfg;
@@ -3375,7 +3331,7 @@ static void set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
 
        dest = set_desc_affinity(desc, mask);
        if (dest == BAD_APICID)
-               return;
+               return -1;
 
        cfg = desc->chip_data;
 
@@ -3387,13 +3343,15 @@ static void set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
        msg.address_lo |= MSI_ADDR_DEST_ID(dest);
 
        write_msi_msg_desc(desc, &msg);
+
+       return 0;
 }
 #ifdef CONFIG_INTR_REMAP
 /*
  * Migrate the MSI irq to another cpumask. This migration is
  * done in the process context using interrupt-remapping hardware.
  */
-static void
+static int
 ir_set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
 {
        struct irq_desc *desc = irq_to_desc(irq);
@@ -3402,11 +3360,11 @@ ir_set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
        struct irte irte;
 
        if (get_irte(irq, &irte))
-               return;
+               return -1;
 
        dest = set_desc_affinity(desc, mask);
        if (dest == BAD_APICID)
-               return;
+               return -1;
 
        irte.vector = cfg->vector;
        irte.dest_id = IRTE_DEST(dest);
@@ -3423,6 +3381,8 @@ ir_set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
         */
        if (cfg->move_in_progress)
                send_cleanup_vector(cfg);
+
+       return 0;
 }
 
 #endif
@@ -3518,15 +3478,17 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
        unsigned int irq_want;
        struct intel_iommu *iommu = NULL;
        int index = 0;
+       int node;
 
        /* x86 doesn't support multiple MSI yet */
        if (type == PCI_CAP_ID_MSI && nvec > 1)
                return 1;
 
+       node = dev_to_node(&dev->dev);
        irq_want = nr_irqs_gsi;
        sub_handle = 0;
        list_for_each_entry(msidesc, &dev->msi_list, list) {
-               irq = create_irq_nr(irq_want);
+               irq = create_irq_nr(irq_want, node);
                if (irq == 0)
                        return -1;
                irq_want = irq + 1;
@@ -3576,7 +3538,7 @@ void arch_teardown_msi_irq(unsigned int irq)
 
 #if defined (CONFIG_DMAR) || defined (CONFIG_INTR_REMAP)
 #ifdef CONFIG_SMP
-static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
+static int dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
 {
        struct irq_desc *desc = irq_to_desc(irq);
        struct irq_cfg *cfg;
@@ -3585,7 +3547,7 @@ static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
 
        dest = set_desc_affinity(desc, mask);
        if (dest == BAD_APICID)
-               return;
+               return -1;
 
        cfg = desc->chip_data;
 
@@ -3597,6 +3559,8 @@ static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
        msg.address_lo |= MSI_ADDR_DEST_ID(dest);
 
        dmar_msi_write(irq, &msg);
+
+       return 0;
 }
 
 #endif /* CONFIG_SMP */
@@ -3630,7 +3594,7 @@ int arch_setup_dmar_msi(unsigned int irq)
 #ifdef CONFIG_HPET_TIMER
 
 #ifdef CONFIG_SMP
-static void hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
+static int hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
 {
        struct irq_desc *desc = irq_to_desc(irq);
        struct irq_cfg *cfg;
@@ -3639,7 +3603,7 @@ static void hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
 
        dest = set_desc_affinity(desc, mask);
        if (dest == BAD_APICID)
-               return;
+               return -1;
 
        cfg = desc->chip_data;
 
@@ -3651,6 +3615,8 @@ static void hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
        msg.address_lo |= MSI_ADDR_DEST_ID(dest);
 
        hpet_msi_write(irq, &msg);
+
+       return 0;
 }
 
 #endif /* CONFIG_SMP */
@@ -3707,7 +3673,7 @@ static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
        write_ht_irq_msg(irq, &msg);
 }
 
-static void set_ht_irq_affinity(unsigned int irq, const struct cpumask *mask)
+static int set_ht_irq_affinity(unsigned int irq, const struct cpumask *mask)
 {
        struct irq_desc *desc = irq_to_desc(irq);
        struct irq_cfg *cfg;
@@ -3715,11 +3681,13 @@ static void set_ht_irq_affinity(unsigned int irq, const struct cpumask *mask)
 
        dest = set_desc_affinity(desc, mask);
        if (dest == BAD_APICID)
-               return;
+               return -1;
 
        cfg = desc->chip_data;
 
        target_ht_irq(irq, dest, cfg->vector);
+
+       return 0;
 }
 
 #endif
@@ -3794,6 +3762,8 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
        unsigned long flags;
        int err;
 
+       BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
+
        cfg = irq_cfg(irq);
 
        err = assign_irq_vector(irq, cfg, eligible_cpu);
@@ -3807,15 +3777,13 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
 
        mmr_value = 0;
        entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
-       BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
-
-       entry->vector = cfg->vector;
-       entry->delivery_mode = apic->irq_delivery_mode;
-       entry->dest_mode = apic->irq_dest_mode;
-       entry->polarity = 0;
-       entry->trigger = 0;
-       entry->mask = 0;
-       entry->dest = apic->cpu_mask_to_apicid(eligible_cpu);
+       entry->vector           = cfg->vector;
+       entry->delivery_mode    = apic->irq_delivery_mode;
+       entry->dest_mode        = apic->irq_dest_mode;
+       entry->polarity         = 0;
+       entry->trigger          = 0;
+       entry->mask             = 0;
+       entry->dest             = apic->cpu_mask_to_apicid(eligible_cpu);
 
        mmr_pnode = uv_blade_to_pnode(mmr_blade);
        uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
@@ -3833,10 +3801,10 @@ void arch_disable_uv_irq(int mmr_blade, unsigned long mmr_offset)
        struct uv_IO_APIC_route_entry *entry;
        int mmr_pnode;
 
+       BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
+
        mmr_value = 0;
        entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
-       BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
-
        entry->mask = 1;
 
        mmr_pnode = uv_blade_to_pnode(mmr_blade);
@@ -3900,6 +3868,71 @@ int __init arch_probe_nr_irqs(void)
 }
 #endif
 
+static int __io_apic_set_pci_routing(struct device *dev, int irq,
+                               struct io_apic_irq_attr *irq_attr)
+{
+       struct irq_desc *desc;
+       struct irq_cfg *cfg;
+       int node;
+       int ioapic, pin;
+       int trigger, polarity;
+
+       ioapic = irq_attr->ioapic;
+       if (!IO_APIC_IRQ(irq)) {
+               apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
+                       ioapic);
+               return -EINVAL;
+       }
+
+       if (dev)
+               node = dev_to_node(dev);
+       else
+               node = cpu_to_node(boot_cpu_id);
+
+       desc = irq_to_desc_alloc_node(irq, node);
+       if (!desc) {
+               printk(KERN_INFO "can not get irq_desc %d\n", irq);
+               return 0;
+       }
+
+       pin = irq_attr->ioapic_pin;
+       trigger = irq_attr->trigger;
+       polarity = irq_attr->polarity;
+
+       /*
+        * IRQs < 16 are already in the irq_2_pin[] map
+        */
+       if (irq >= NR_IRQS_LEGACY) {
+               cfg = desc->chip_data;
+               add_pin_to_irq_node(cfg, node, ioapic, pin);
+       }
+
+       setup_IO_APIC_irq(ioapic, pin, irq, desc, trigger, polarity);
+
+       return 0;
+}
+
+int io_apic_set_pci_routing(struct device *dev, int irq,
+                               struct io_apic_irq_attr *irq_attr)
+{
+       int ioapic, pin;
+       /*
+        * Avoid pin reprogramming.  PRTs typically include entries
+        * with redundant pin->gsi mappings (but unique PCI devices);
+        * we only program the IOAPIC on the first.
+        */
+       ioapic = irq_attr->ioapic;
+       pin = irq_attr->ioapic_pin;
+       if (test_bit(pin, mp_ioapic_routing[ioapic].pin_programmed)) {
+               pr_debug("Pin %d-%d already programmed\n",
+                        mp_ioapics[ioapic].apicid, pin);
+               return 0;
+       }
+       set_bit(pin, mp_ioapic_routing[ioapic].pin_programmed);
+
+       return __io_apic_set_pci_routing(dev, irq, irq_attr);
+}
+
 /* --------------------------------------------------------------------------
                           ACPI-based IOAPIC Configuration
    -------------------------------------------------------------------------- */
@@ -3980,6 +4013,7 @@ int __init io_apic_get_unique_id(int ioapic, int apic_id)
 
        return apic_id;
 }
+#endif
 
 int __init io_apic_get_version(int ioapic)
 {
@@ -3992,39 +4026,6 @@ int __init io_apic_get_version(int ioapic)
 
        return reg_01.bits.version;
 }
-#endif
-
-int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int polarity)
-{
-       struct irq_desc *desc;
-       struct irq_cfg *cfg;
-       int cpu = boot_cpu_id;
-
-       if (!IO_APIC_IRQ(irq)) {
-               apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
-                       ioapic);
-               return -EINVAL;
-       }
-
-       desc = irq_to_desc_alloc_cpu(irq, cpu);
-       if (!desc) {
-               printk(KERN_INFO "can not get irq_desc %d\n", irq);
-               return 0;
-       }
-
-       /*
-        * IRQs < 16 are already in the irq_2_pin[] map
-        */
-       if (irq >= NR_IRQS_LEGACY) {
-               cfg = desc->chip_data;
-               add_pin_to_irq_cpu(cfg, cpu, ioapic, pin);
-       }
-
-       setup_IO_APIC_irq(ioapic, pin, irq, desc, triggering, polarity);
-
-       return 0;
-}
-
 
 int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity)
 {
@@ -4055,51 +4056,44 @@ int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity)
 #ifdef CONFIG_SMP
 void __init setup_ioapic_dest(void)
 {
-       int pin, ioapic, irq, irq_entry;
+       int pin, ioapic = 0, irq, irq_entry;
        struct irq_desc *desc;
-       struct irq_cfg *cfg;
        const struct cpumask *mask;
 
        if (skip_ioapic_setup == 1)
                return;
 
-       for (ioapic = 0; ioapic < nr_ioapics; ioapic++) {
-               for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) {
-                       irq_entry = find_irq_entry(ioapic, pin, mp_INT);
-                       if (irq_entry == -1)
-                               continue;
-                       irq = pin_2_irq(irq_entry, ioapic, pin);
-
-                       /* setup_IO_APIC_irqs could fail to get vector for some device
-                        * when you have too many devices, because at that time only boot
-                        * cpu is online.
-                        */
-                       desc = irq_to_desc(irq);
-                       cfg = desc->chip_data;
-                       if (!cfg->vector) {
-                               setup_IO_APIC_irq(ioapic, pin, irq, desc,
-                                                 irq_trigger(irq_entry),
-                                                 irq_polarity(irq_entry));
-                               continue;
+#ifdef CONFIG_ACPI
+       if (!acpi_disabled && acpi_ioapic) {
+               ioapic = mp_find_ioapic(0);
+               if (ioapic < 0)
+                       ioapic = 0;
+       }
+#endif
 
-                       }
+       for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) {
+               irq_entry = find_irq_entry(ioapic, pin, mp_INT);
+               if (irq_entry == -1)
+                       continue;
+               irq = pin_2_irq(irq_entry, ioapic, pin);
 
-                       /*
-                        * Honour affinities which have been set in early boot
-                        */
-                       if (desc->status &
-                           (IRQ_NO_BALANCING | IRQ_AFFINITY_SET))
-                               mask = desc->affinity;
-                       else
-                               mask = apic->target_cpus();
+               desc = irq_to_desc(irq);
 
-                       if (intr_remapping_enabled)
-                               set_ir_ioapic_affinity_irq_desc(desc, mask);
-                       else
-                               set_ioapic_affinity_irq_desc(desc, mask);
-               }
+               /*
+                * Honour affinities which have been set in early boot
+                */
+               if (desc->status &
+                   (IRQ_NO_BALANCING | IRQ_AFFINITY_SET))
+                       mask = desc->affinity;
+               else
+                       mask = apic->target_cpus();
 
+               if (intr_remapping_enabled)
+                       set_ir_ioapic_affinity_irq_desc(desc, mask);
+               else
+                       set_ioapic_affinity_irq_desc(desc, mask);
        }
+
 }
 #endif
 
index ce4fbfa315a16ac1f4e45f34281121577f5477a6..a691302dc3ffa4e5e4771df1fedf17919d7133c6 100644 (file)
@@ -104,7 +104,7 @@ static __init void nmi_cpu_busy(void *data)
 }
 #endif
 
-static void report_broken_nmi(int cpu, int *prev_nmi_count)
+static void report_broken_nmi(int cpu, unsigned int *prev_nmi_count)
 {
        printk(KERN_CONT "\n");
 
index 01eda2ac65e4d9620b19979a0a24ef4636cae889..440a8bccd91ad7ac8ae326f48fb30cab6e007b20 100644 (file)
@@ -160,7 +160,6 @@ extern struct apic apic_summit;
 extern struct apic apic_bigsmp;
 extern struct apic apic_es7000;
 extern struct apic apic_es7000_cluster;
-extern struct apic apic_default;
 
 struct apic *apic = &apic_default;
 EXPORT_SYMBOL_GPL(apic);
index 1783652bb0e56c8140e411a4ba5643a64ab4d0fc..bc3e880f9b82e76902b305d10920b70b05c440ac 100644 (file)
@@ -50,7 +50,7 @@ static struct apic *apic_probe[] __initdata = {
 void __init default_setup_apic_routing(void)
 {
 #ifdef CONFIG_X86_X2APIC
-       if (x2apic && (apic != &apic_x2apic_phys &&
+       if (x2apic_mode && (apic != &apic_x2apic_phys &&
 #ifdef CONFIG_X86_UV
                       apic != &apic_x2apic_uv_x &&
 #endif
index 9cfe1f415d81f3659f1f68b8f88dcb4365be3ff7..344eee4ac0a48242d64db5676ec38fbe92d42c73 100644 (file)
@@ -173,13 +173,6 @@ static inline int is_WPEG(struct rio_detail *rio){
                rio->type == LookOutAWPEG || rio->type == LookOutBWPEG);
 }
 
-
-/* In clustered mode, the high nibble of APIC ID is a cluster number.
- * The low nibble is a 4-bit bitmap. */
-#define XAPIC_DEST_CPUS_SHIFT  4
-#define XAPIC_DEST_CPUS_MASK   ((1u << XAPIC_DEST_CPUS_SHIFT) - 1)
-#define XAPIC_DEST_CLUSTER_MASK        (XAPIC_DEST_CPUS_MASK << XAPIC_DEST_CPUS_SHIFT)
-
 #define SUMMIT_APIC_DFR_VALUE  (APIC_DFR_CLUSTER)
 
 static const struct cpumask *summit_target_cpus(void)
index 4a903e2f0d179d68d6a30f5afe7c1b0543a45870..8e4cbb255c38d289f78083828845da5ae43b06ac 100644 (file)
@@ -10,7 +10,7 @@
 #include <asm/apic.h>
 #include <asm/ipi.h>
 
-DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid);
+static DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid);
 
 static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
index 2bda693529762b71f30ae2c26fa08a7692ca5cb5..ef0ae207a7c82cb64f7a0a7758a91dc22b0f8fee 100644 (file)
@@ -105,7 +105,7 @@ static void uv_vector_allocation_domain(int cpu, struct cpumask *retmask)
        cpumask_set_cpu(cpu, retmask);
 }
 
-static int uv_wakeup_secondary(int phys_apicid, unsigned long start_rip)
+static int __cpuinit uv_wakeup_secondary(int phys_apicid, unsigned long start_rip)
 {
 #ifdef CONFIG_SMP
        unsigned long val;
@@ -562,7 +562,7 @@ void __init uv_system_init(void)
        union uvh_node_id_u node_id;
        unsigned long gnode_upper, lowmem_redir_base, lowmem_redir_size;
        int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val;
-       int max_pnode = 0;
+       int gnode_extra, max_pnode = 0;
        unsigned long mmr_base, present, paddr;
        unsigned short pnode_mask;
 
@@ -574,6 +574,13 @@ void __init uv_system_init(void)
        mmr_base =
            uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
            ~UV_MMR_ENABLE;
+       pnode_mask = (1 << n_val) - 1;
+       node_id.v = uv_read_local_mmr(UVH_NODE_ID);
+       gnode_extra = (node_id.s.node_id & ~((1 << n_val) - 1)) >> 1;
+       gnode_upper = ((unsigned long)gnode_extra  << m_val);
+       printk(KERN_DEBUG "UV: N %d, M %d, gnode_upper 0x%lx, gnode_extra 0x%x\n",
+                       n_val, m_val, gnode_upper, gnode_extra);
+
        printk(KERN_DEBUG "UV: global MMR base 0x%lx\n", mmr_base);
 
        for(i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++)
@@ -583,15 +590,18 @@ void __init uv_system_init(void)
 
        bytes = sizeof(struct uv_blade_info) * uv_num_possible_blades();
        uv_blade_info = kmalloc(bytes, GFP_KERNEL);
+       BUG_ON(!uv_blade_info);
 
        get_lowmem_redirect(&lowmem_redir_base, &lowmem_redir_size);
 
        bytes = sizeof(uv_node_to_blade[0]) * num_possible_nodes();
        uv_node_to_blade = kmalloc(bytes, GFP_KERNEL);
+       BUG_ON(!uv_node_to_blade);
        memset(uv_node_to_blade, 255, bytes);
 
        bytes = sizeof(uv_cpu_to_blade[0]) * num_possible_cpus();
        uv_cpu_to_blade = kmalloc(bytes, GFP_KERNEL);
+       BUG_ON(!uv_cpu_to_blade);
        memset(uv_cpu_to_blade, 255, bytes);
 
        blade = 0;
@@ -607,11 +617,6 @@ void __init uv_system_init(void)
                }
        }
 
-       pnode_mask = (1 << n_val) - 1;
-       node_id.v = uv_read_local_mmr(UVH_NODE_ID);
-       gnode_upper = (((unsigned long)node_id.s.node_id) &
-                      ~((1 << n_val) - 1)) << m_val;
-
        uv_bios_init();
        uv_bios_get_sn_info(0, &uv_type, &sn_partition_id,
                            &sn_coherency_id, &sn_region_size);
@@ -634,6 +639,7 @@ void __init uv_system_init(void)
                uv_cpu_hub_info(cpu)->pnode_mask = pnode_mask;
                uv_cpu_hub_info(cpu)->gpa_mask = (1 << (m_val + n_val)) - 1;
                uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper;
+               uv_cpu_hub_info(cpu)->gnode_extra = gnode_extra;
                uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base;
                uv_cpu_hub_info(cpu)->coherency_domain_number = sn_coherency_id;
                uv_cpu_hub_info(cpu)->scir.offset = SCIR_LOCAL_MMR_BASE + lcpu;
index 5a6aa1c1162f06492a27cee3ac754b16e7fa57e0..1a830cbd70153b8662eddf16a87a5336c6cb0742 100644 (file)
@@ -146,4 +146,5 @@ void foo(void)
        OFFSET(BP_loadflags, boot_params, hdr.loadflags);
        OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch);
        OFFSET(BP_version, boot_params, hdr.version);
+       OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment);
 }
index e72f062fb4b5fd841617a3e7f7c766e64bf4428f..898ecc47e129e8f8e0848287a518f2af137f022b 100644 (file)
@@ -125,6 +125,7 @@ int main(void)
        OFFSET(BP_loadflags, boot_params, hdr.loadflags);
        OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch);
        OFFSET(BP_version, boot_params, hdr.version);
+       OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment);
 
        BLANK();
        DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
index 7e4a459daa644f30309f50e9ca65ece4be85fad7..e5b27d8f1b47395fda285d867b776e82454ae61a 100644 (file)
@@ -6,6 +6,7 @@
 #include <asm/processor.h>
 #include <asm/apic.h>
 #include <asm/cpu.h>
+#include <asm/pci-direct.h>
 
 #ifdef CONFIG_X86_64
 # include <asm/numa_64.h>
@@ -272,7 +273,7 @@ static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c)
 #if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
        int cpu = smp_processor_id();
        int node;
-       unsigned apicid = hard_smp_processor_id();
+       unsigned apicid = cpu_has_apic ? hard_smp_processor_id() : c->apicid;
 
        node = c->phys_proc_id;
        if (apicid_to_node[apicid] != NUMA_NO_NODE)
@@ -351,6 +352,15 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
                    (c->x86_model == 8 && c->x86_mask >= 8))
                        set_cpu_cap(c, X86_FEATURE_K6_MTRR);
 #endif
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PCI)
+       /* check CPU config space for extended APIC ID */
+       if (c->x86 >= 0xf) {
+               unsigned int val;
+               val = read_pci_config(0, 24, 0, 0x68);
+               if ((val & ((1 << 17) | (1 << 18))) == ((1 << 17) | (1 << 18)))
+                       set_cpu_cap(c, X86_FEATURE_EXTD_APICID);
+       }
+#endif
 }
 
 static void __cpuinit init_amd(struct cpuinfo_x86 *c)
index 77848d9fca6833fa88488adb6e22cae027a7d6c1..b0517aa2bd3b37455c265bb415517f2a38eef20d 100644 (file)
@@ -299,7 +299,8 @@ static const char *__cpuinit table_lookup_model(struct cpuinfo_x86 *c)
        return NULL;            /* Not found */
 }
 
-__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata;
+__u32 cpu_caps_cleared[NCAPINTS] __cpuinitdata;
+__u32 cpu_caps_set[NCAPINTS] __cpuinitdata;
 
 void load_percpu_segment(int cpu)
 {
@@ -768,6 +769,12 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
        if (this_cpu->c_identify)
                this_cpu->c_identify(c);
 
+       /* Clear/Set all flags overriden by options, after probe */
+       for (i = 0; i < NCAPINTS; i++) {
+               c->x86_capability[i] &= ~cpu_caps_cleared[i];
+               c->x86_capability[i] |= cpu_caps_set[i];
+       }
+
 #ifdef CONFIG_X86_64
        c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
 #endif
@@ -813,6 +820,16 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
 #endif
 
        init_hypervisor(c);
+
+       /*
+        * Clear/Set all flags overriden by options, need do it
+        * before following smp all cpus cap AND.
+        */
+       for (i = 0; i < NCAPINTS; i++) {
+               c->x86_capability[i] &= ~cpu_caps_cleared[i];
+               c->x86_capability[i] |= cpu_caps_set[i];
+       }
+
        /*
         * On SMP, boot_cpu_data holds the common feature set between
         * all CPUs; so make sure that we indicate which features are
@@ -825,10 +842,6 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
                        boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
        }
 
-       /* Clear all flags overriden by options */
-       for (i = 0; i < NCAPINTS; i++)
-               c->x86_capability[i] &= ~cleared_cpu_caps[i];
-
 #ifdef CONFIG_X86_MCE
        /* Init Machine Check Exception if available. */
        mcheck_init(c);
index 46e29ab96c6ac9d6765f0f1a89e7c043ed2f5cbd..6b2a52dd040398f36374926956875078c3e48f95 100644 (file)
@@ -32,9 +32,7 @@
 
 static DEFINE_PER_CPU(struct cpu_cpuX_base, cpu_arr[CPU_REG_ALL_BIT]);
 static DEFINE_PER_CPU(struct cpu_private *, priv_arr[MAX_CPU_FILES]);
-static DEFINE_PER_CPU(unsigned, cpu_modelflag);
 static DEFINE_PER_CPU(int, cpu_priv_count);
-static DEFINE_PER_CPU(unsigned, cpu_model);
 
 static DEFINE_MUTEX(cpu_debug_lock);
 
@@ -80,302 +78,102 @@ static struct cpu_file_base cpu_file[] = {
        { "value",      CPU_REG_ALL,    1       },
 };
 
-/* Intel Registers Range */
-static struct cpu_debug_range cpu_intel_range[] = {
-       { 0x00000000, 0x00000001, CPU_MC,       CPU_INTEL_ALL           },
-       { 0x00000006, 0x00000007, CPU_MONITOR,  CPU_CX_AT_XE            },
-       { 0x00000010, 0x00000010, CPU_TIME,     CPU_INTEL_ALL           },
-       { 0x00000011, 0x00000013, CPU_PMC,      CPU_INTEL_PENTIUM       },
-       { 0x00000017, 0x00000017, CPU_PLATFORM, CPU_PX_CX_AT_XE         },
-       { 0x0000001B, 0x0000001B, CPU_APIC,     CPU_P6_CX_AT_XE         },
-
-       { 0x0000002A, 0x0000002A, CPU_POWERON,  CPU_PX_CX_AT_XE         },
-       { 0x0000002B, 0x0000002B, CPU_POWERON,  CPU_INTEL_XEON          },
-       { 0x0000002C, 0x0000002C, CPU_FREQ,     CPU_INTEL_XEON          },
-       { 0x0000003A, 0x0000003A, CPU_CONTROL,  CPU_CX_AT_XE            },
-
-       { 0x00000040, 0x00000043, CPU_LBRANCH,  CPU_PM_CX_AT_XE         },
-       { 0x00000044, 0x00000047, CPU_LBRANCH,  CPU_PM_CO_AT            },
-       { 0x00000060, 0x00000063, CPU_LBRANCH,  CPU_C2_AT               },
-       { 0x00000064, 0x00000067, CPU_LBRANCH,  CPU_INTEL_ATOM          },
-
-       { 0x00000079, 0x00000079, CPU_BIOS,     CPU_P6_CX_AT_XE         },
-       { 0x00000088, 0x0000008A, CPU_CACHE,    CPU_INTEL_P6            },
-       { 0x0000008B, 0x0000008B, CPU_BIOS,     CPU_P6_CX_AT_XE         },
-       { 0x0000009B, 0x0000009B, CPU_MONITOR,  CPU_INTEL_XEON          },
-
-       { 0x000000C1, 0x000000C2, CPU_PMC,      CPU_P6_CX_AT            },
-       { 0x000000CD, 0x000000CD, CPU_FREQ,     CPU_CX_AT               },
-       { 0x000000E7, 0x000000E8, CPU_PERF,     CPU_CX_AT               },
-       { 0x000000FE, 0x000000FE, CPU_MTRR,     CPU_P6_CX_XE            },
-
-       { 0x00000116, 0x00000116, CPU_CACHE,    CPU_INTEL_P6            },
-       { 0x00000118, 0x00000118, CPU_CACHE,    CPU_INTEL_P6            },
-       { 0x00000119, 0x00000119, CPU_CACHE,    CPU_INTEL_PX            },
-       { 0x0000011A, 0x0000011B, CPU_CACHE,    CPU_INTEL_P6            },
-       { 0x0000011E, 0x0000011E, CPU_CACHE,    CPU_PX_CX_AT            },
-
-       { 0x00000174, 0x00000176, CPU_SYSENTER, CPU_P6_CX_AT_XE         },
-       { 0x00000179, 0x0000017A, CPU_MC,       CPU_PX_CX_AT_XE         },
-       { 0x0000017B, 0x0000017B, CPU_MC,       CPU_P6_XE               },
-       { 0x00000186, 0x00000187, CPU_PMC,      CPU_P6_CX_AT            },
-       { 0x00000198, 0x00000199, CPU_PERF,     CPU_PM_CX_AT_XE         },
-       { 0x0000019A, 0x0000019A, CPU_TIME,     CPU_PM_CX_AT_XE         },
-       { 0x0000019B, 0x0000019D, CPU_THERM,    CPU_PM_CX_AT_XE         },
-       { 0x000001A0, 0x000001A0, CPU_MISC,     CPU_PM_CX_AT_XE         },
-
-       { 0x000001C9, 0x000001C9, CPU_LBRANCH,  CPU_PM_CX_AT            },
-       { 0x000001D7, 0x000001D8, CPU_LBRANCH,  CPU_INTEL_XEON          },
-       { 0x000001D9, 0x000001D9, CPU_DEBUG,    CPU_CX_AT_XE            },
-       { 0x000001DA, 0x000001DA, CPU_LBRANCH,  CPU_INTEL_XEON          },
-       { 0x000001DB, 0x000001DB, CPU_LBRANCH,  CPU_P6_XE               },
-       { 0x000001DC, 0x000001DC, CPU_LBRANCH,  CPU_INTEL_P6            },
-       { 0x000001DD, 0x000001DE, CPU_LBRANCH,  CPU_PX_CX_AT_XE         },
-       { 0x000001E0, 0x000001E0, CPU_LBRANCH,  CPU_INTEL_P6            },
-
-       { 0x00000200, 0x0000020F, CPU_MTRR,     CPU_P6_CX_XE            },
-       { 0x00000250, 0x00000250, CPU_MTRR,     CPU_P6_CX_XE            },
-       { 0x00000258, 0x00000259, CPU_MTRR,     CPU_P6_CX_XE            },
-       { 0x00000268, 0x0000026F, CPU_MTRR,     CPU_P6_CX_XE            },
-       { 0x00000277, 0x00000277, CPU_PAT,      CPU_C2_AT_XE            },
-       { 0x000002FF, 0x000002FF, CPU_MTRR,     CPU_P6_CX_XE            },
-
-       { 0x00000300, 0x00000308, CPU_PMC,      CPU_INTEL_XEON          },
-       { 0x00000309, 0x0000030B, CPU_PMC,      CPU_C2_AT_XE            },
-       { 0x0000030C, 0x00000311, CPU_PMC,      CPU_INTEL_XEON          },
-       { 0x00000345, 0x00000345, CPU_PMC,      CPU_C2_AT               },
-       { 0x00000360, 0x00000371, CPU_PMC,      CPU_INTEL_XEON          },
-       { 0x0000038D, 0x00000390, CPU_PMC,      CPU_C2_AT               },
-       { 0x000003A0, 0x000003BE, CPU_PMC,      CPU_INTEL_XEON          },
-       { 0x000003C0, 0x000003CD, CPU_PMC,      CPU_INTEL_XEON          },
-       { 0x000003E0, 0x000003E1, CPU_PMC,      CPU_INTEL_XEON          },
-       { 0x000003F0, 0x000003F0, CPU_PMC,      CPU_INTEL_XEON          },
-       { 0x000003F1, 0x000003F1, CPU_PMC,      CPU_C2_AT_XE            },
-       { 0x000003F2, 0x000003F2, CPU_PMC,      CPU_INTEL_XEON          },
-
-       { 0x00000400, 0x00000402, CPU_MC,       CPU_PM_CX_AT_XE         },
-       { 0x00000403, 0x00000403, CPU_MC,       CPU_INTEL_XEON          },
-       { 0x00000404, 0x00000406, CPU_MC,       CPU_PM_CX_AT_XE         },
-       { 0x00000407, 0x00000407, CPU_MC,       CPU_INTEL_XEON          },
-       { 0x00000408, 0x0000040A, CPU_MC,       CPU_PM_CX_AT_XE         },
-       { 0x0000040B, 0x0000040B, CPU_MC,       CPU_INTEL_XEON          },
-       { 0x0000040C, 0x0000040E, CPU_MC,       CPU_PM_CX_XE            },
-       { 0x0000040F, 0x0000040F, CPU_MC,       CPU_INTEL_XEON          },
-       { 0x00000410, 0x00000412, CPU_MC,       CPU_PM_CX_AT_XE         },
-       { 0x00000413, 0x00000417, CPU_MC,       CPU_CX_AT_XE            },
-       { 0x00000480, 0x0000048B, CPU_VMX,      CPU_CX_AT_XE            },
-
-       { 0x00000600, 0x00000600, CPU_DEBUG,    CPU_PM_CX_AT_XE         },
-       { 0x00000680, 0x0000068F, CPU_LBRANCH,  CPU_INTEL_XEON          },
-       { 0x000006C0, 0x000006CF, CPU_LBRANCH,  CPU_INTEL_XEON          },
-
-       { 0x000107CC, 0x000107D3, CPU_PMC,      CPU_INTEL_XEON_MP       },
-
-       { 0xC0000080, 0xC0000080, CPU_FEATURES, CPU_INTEL_XEON          },
-       { 0xC0000081, 0xC0000082, CPU_CALL,     CPU_INTEL_XEON          },
-       { 0xC0000084, 0xC0000084, CPU_CALL,     CPU_INTEL_XEON          },
-       { 0xC0000100, 0xC0000102, CPU_BASE,     CPU_INTEL_XEON          },
+/* CPU Registers Range */
+static struct cpu_debug_range cpu_reg_range[] = {
+       { 0x00000000, 0x00000001, CPU_MC,       },
+       { 0x00000006, 0x00000007, CPU_MONITOR,  },
+       { 0x00000010, 0x00000010, CPU_TIME,     },
+       { 0x00000011, 0x00000013, CPU_PMC,      },
+       { 0x00000017, 0x00000017, CPU_PLATFORM, },
+       { 0x0000001B, 0x0000001B, CPU_APIC,     },
+       { 0x0000002A, 0x0000002B, CPU_POWERON,  },
+       { 0x0000002C, 0x0000002C, CPU_FREQ,     },
+       { 0x0000003A, 0x0000003A, CPU_CONTROL,  },
+       { 0x00000040, 0x00000047, CPU_LBRANCH,  },
+       { 0x00000060, 0x00000067, CPU_LBRANCH,  },
+       { 0x00000079, 0x00000079, CPU_BIOS,     },
+       { 0x00000088, 0x0000008A, CPU_CACHE,    },
+       { 0x0000008B, 0x0000008B, CPU_BIOS,     },
+       { 0x0000009B, 0x0000009B, CPU_MONITOR,  },
+       { 0x000000C1, 0x000000C4, CPU_PMC,      },
+       { 0x000000CD, 0x000000CD, CPU_FREQ,     },
+       { 0x000000E7, 0x000000E8, CPU_PERF,     },
+       { 0x000000FE, 0x000000FE, CPU_MTRR,     },
+
+       { 0x00000116, 0x0000011E, CPU_CACHE,    },
+       { 0x00000174, 0x00000176, CPU_SYSENTER, },
+       { 0x00000179, 0x0000017B, CPU_MC,       },
+       { 0x00000186, 0x00000189, CPU_PMC,      },
+       { 0x00000198, 0x00000199, CPU_PERF,     },
+       { 0x0000019A, 0x0000019A, CPU_TIME,     },
+       { 0x0000019B, 0x0000019D, CPU_THERM,    },
+       { 0x000001A0, 0x000001A0, CPU_MISC,     },
+       { 0x000001C9, 0x000001C9, CPU_LBRANCH,  },
+       { 0x000001D7, 0x000001D8, CPU_LBRANCH,  },
+       { 0x000001D9, 0x000001D9, CPU_DEBUG,    },
+       { 0x000001DA, 0x000001E0, CPU_LBRANCH,  },
+
+       { 0x00000200, 0x0000020F, CPU_MTRR,     },
+       { 0x00000250, 0x00000250, CPU_MTRR,     },
+       { 0x00000258, 0x00000259, CPU_MTRR,     },
+       { 0x00000268, 0x0000026F, CPU_MTRR,     },
+       { 0x00000277, 0x00000277, CPU_PAT,      },
+       { 0x000002FF, 0x000002FF, CPU_MTRR,     },
+
+       { 0x00000300, 0x00000311, CPU_PMC,      },
+       { 0x00000345, 0x00000345, CPU_PMC,      },
+       { 0x00000360, 0x00000371, CPU_PMC,      },
+       { 0x0000038D, 0x00000390, CPU_PMC,      },
+       { 0x000003A0, 0x000003BE, CPU_PMC,      },
+       { 0x000003C0, 0x000003CD, CPU_PMC,      },
+       { 0x000003E0, 0x000003E1, CPU_PMC,      },
+       { 0x000003F0, 0x000003F2, CPU_PMC,      },
+
+       { 0x00000400, 0x00000417, CPU_MC,       },
+       { 0x00000480, 0x0000048B, CPU_VMX,      },
+
+       { 0x00000600, 0x00000600, CPU_DEBUG,    },
+       { 0x00000680, 0x0000068F, CPU_LBRANCH,  },
+       { 0x000006C0, 0x000006CF, CPU_LBRANCH,  },
+
+       { 0x000107CC, 0x000107D3, CPU_PMC,      },
+
+       { 0xC0000080, 0xC0000080, CPU_FEATURES, },
+       { 0xC0000081, 0xC0000084, CPU_CALL,     },
+       { 0xC0000100, 0xC0000102, CPU_BASE,     },
+       { 0xC0000103, 0xC0000103, CPU_TIME,     },
+
+       { 0xC0010000, 0xC0010007, CPU_PMC,      },
+       { 0xC0010010, 0xC0010010, CPU_CONF,     },
+       { 0xC0010015, 0xC0010015, CPU_CONF,     },
+       { 0xC0010016, 0xC001001A, CPU_MTRR,     },
+       { 0xC001001D, 0xC001001D, CPU_MTRR,     },
+       { 0xC001001F, 0xC001001F, CPU_CONF,     },
+       { 0xC0010030, 0xC0010035, CPU_BIOS,     },
+       { 0xC0010044, 0xC0010048, CPU_MC,       },
+       { 0xC0010050, 0xC0010056, CPU_SMM,      },
+       { 0xC0010058, 0xC0010058, CPU_CONF,     },
+       { 0xC0010060, 0xC0010060, CPU_CACHE,    },
+       { 0xC0010061, 0xC0010068, CPU_SMM,      },
+       { 0xC0010069, 0xC001006B, CPU_SMM,      },
+       { 0xC0010070, 0xC0010071, CPU_SMM,      },
+       { 0xC0010111, 0xC0010113, CPU_SMM,      },
+       { 0xC0010114, 0xC0010118, CPU_SVM,      },
+       { 0xC0010140, 0xC0010141, CPU_OSVM,     },
+       { 0xC0011022, 0xC0011023, CPU_CONF,     },
 };
 
-/* AMD Registers Range */
-static struct cpu_debug_range cpu_amd_range[] = {
-       { 0x00000000, 0x00000001, CPU_MC,       CPU_K10_PLUS,           },
-       { 0x00000010, 0x00000010, CPU_TIME,     CPU_K8_PLUS,            },
-       { 0x0000001B, 0x0000001B, CPU_APIC,     CPU_K8_PLUS,            },
-       { 0x0000002A, 0x0000002A, CPU_POWERON,  CPU_K7_PLUS             },
-       { 0x0000008B, 0x0000008B, CPU_VER,      CPU_K8_PLUS             },
-       { 0x000000FE, 0x000000FE, CPU_MTRR,     CPU_K8_PLUS,            },
-
-       { 0x00000174, 0x00000176, CPU_SYSENTER, CPU_K8_PLUS,            },
-       { 0x00000179, 0x0000017B, CPU_MC,       CPU_K8_PLUS,            },
-       { 0x000001D9, 0x000001D9, CPU_DEBUG,    CPU_K8_PLUS,            },
-       { 0x000001DB, 0x000001DE, CPU_LBRANCH,  CPU_K8_PLUS,            },
-
-       { 0x00000200, 0x0000020F, CPU_MTRR,     CPU_K8_PLUS,            },
-       { 0x00000250, 0x00000250, CPU_MTRR,     CPU_K8_PLUS,            },
-       { 0x00000258, 0x00000259, CPU_MTRR,     CPU_K8_PLUS,            },
-       { 0x00000268, 0x0000026F, CPU_MTRR,     CPU_K8_PLUS,            },
-       { 0x00000277, 0x00000277, CPU_PAT,      CPU_K8_PLUS,            },
-       { 0x000002FF, 0x000002FF, CPU_MTRR,     CPU_K8_PLUS,            },
-
-       { 0x00000400, 0x00000413, CPU_MC,       CPU_K8_PLUS,            },
-
-       { 0xC0000080, 0xC0000080, CPU_FEATURES, CPU_AMD_ALL,            },
-       { 0xC0000081, 0xC0000084, CPU_CALL,     CPU_K8_PLUS,            },
-       { 0xC0000100, 0xC0000102, CPU_BASE,     CPU_K8_PLUS,            },
-       { 0xC0000103, 0xC0000103, CPU_TIME,     CPU_K10_PLUS,           },
-
-       { 0xC0010000, 0xC0010007, CPU_PMC,      CPU_K8_PLUS,            },
-       { 0xC0010010, 0xC0010010, CPU_CONF,     CPU_K7_PLUS,            },
-       { 0xC0010015, 0xC0010015, CPU_CONF,     CPU_K7_PLUS,            },
-       { 0xC0010016, 0xC001001A, CPU_MTRR,     CPU_K8_PLUS,            },
-       { 0xC001001D, 0xC001001D, CPU_MTRR,     CPU_K8_PLUS,            },
-       { 0xC001001F, 0xC001001F, CPU_CONF,     CPU_K8_PLUS,            },
-       { 0xC0010030, 0xC0010035, CPU_BIOS,     CPU_K8_PLUS,            },
-       { 0xC0010044, 0xC0010048, CPU_MC,       CPU_K8_PLUS,            },
-       { 0xC0010050, 0xC0010056, CPU_SMM,      CPU_K0F_PLUS,           },
-       { 0xC0010058, 0xC0010058, CPU_CONF,     CPU_K10_PLUS,           },
-       { 0xC0010060, 0xC0010060, CPU_CACHE,    CPU_AMD_11,             },
-       { 0xC0010061, 0xC0010068, CPU_SMM,      CPU_K10_PLUS,           },
-       { 0xC0010069, 0xC001006B, CPU_SMM,      CPU_AMD_11,             },
-       { 0xC0010070, 0xC0010071, CPU_SMM,      CPU_K10_PLUS,           },
-       { 0xC0010111, 0xC0010113, CPU_SMM,      CPU_K8_PLUS,            },
-       { 0xC0010114, 0xC0010118, CPU_SVM,      CPU_K10_PLUS,           },
-       { 0xC0010140, 0xC0010141, CPU_OSVM,     CPU_K10_PLUS,           },
-       { 0xC0011022, 0xC0011023, CPU_CONF,     CPU_K10_PLUS,           },
-};
-
-
-/* Intel */
-static int get_intel_modelflag(unsigned model)
-{
-       int flag;
-
-       switch (model) {
-       case 0x0501:
-       case 0x0502:
-       case 0x0504:
-               flag = CPU_INTEL_PENTIUM;
-               break;
-       case 0x0601:
-       case 0x0603:
-       case 0x0605:
-       case 0x0607:
-       case 0x0608:
-       case 0x060A:
-       case 0x060B:
-               flag = CPU_INTEL_P6;
-               break;
-       case 0x0609:
-       case 0x060D:
-               flag = CPU_INTEL_PENTIUM_M;
-               break;
-       case 0x060E:
-               flag = CPU_INTEL_CORE;
-               break;
-       case 0x060F:
-       case 0x0617:
-               flag = CPU_INTEL_CORE2;
-               break;
-       case 0x061C:
-               flag = CPU_INTEL_ATOM;
-               break;
-       case 0x0F00:
-       case 0x0F01:
-       case 0x0F02:
-       case 0x0F03:
-       case 0x0F04:
-               flag = CPU_INTEL_XEON_P4;
-               break;
-       case 0x0F06:
-               flag = CPU_INTEL_XEON_MP;
-               break;
-       default:
-               flag = CPU_NONE;
-               break;
-       }
-
-       return flag;
-}
-
-/* AMD */
-static int get_amd_modelflag(unsigned model)
-{
-       int flag;
-
-       switch (model >> 8) {
-       case 0x6:
-               flag = CPU_AMD_K6;
-               break;
-       case 0x7:
-               flag = CPU_AMD_K7;
-               break;
-       case 0x8:
-               flag = CPU_AMD_K8;
-               break;
-       case 0xf:
-               flag = CPU_AMD_0F;
-               break;
-       case 0x10:
-               flag = CPU_AMD_10;
-               break;
-       case 0x11:
-               flag = CPU_AMD_11;
-               break;
-       default:
-               flag = CPU_NONE;
-               break;
-       }
-
-       return flag;
-}
-
-static int get_cpu_modelflag(unsigned cpu)
-{
-       int flag;
-
-       flag = per_cpu(cpu_model, cpu);
-
-       switch (flag >> 16) {
-       case X86_VENDOR_INTEL:
-               flag = get_intel_modelflag(flag);
-               break;
-       case X86_VENDOR_AMD:
-               flag = get_amd_modelflag(flag & 0xffff);
-               break;
-       default:
-               flag = CPU_NONE;
-               break;
-       }
-
-       return flag;
-}
-
-static int get_cpu_range_count(unsigned cpu)
-{
-       int index;
-
-       switch (per_cpu(cpu_model, cpu) >> 16) {
-       case X86_VENDOR_INTEL:
-               index = ARRAY_SIZE(cpu_intel_range);
-               break;
-       case X86_VENDOR_AMD:
-               index = ARRAY_SIZE(cpu_amd_range);
-               break;
-       default:
-               index = 0;
-               break;
-       }
-
-       return index;
-}
-
 static int is_typeflag_valid(unsigned cpu, unsigned flag)
 {
-       unsigned vendor, modelflag;
-       int i, index;
+       int i;
 
        /* Standard Registers should be always valid */
        if (flag >= CPU_TSS)
                return 1;
 
-       modelflag = per_cpu(cpu_modelflag, cpu);
-       vendor = per_cpu(cpu_model, cpu) >> 16;
-       index = get_cpu_range_count(cpu);
-
-       for (i = 0; i < index; i++) {
-               switch (vendor) {
-               case X86_VENDOR_INTEL:
-                       if ((cpu_intel_range[i].model & modelflag) &&
-                           (cpu_intel_range[i].flag & flag))
-                               return 1;
-                       break;
-               case X86_VENDOR_AMD:
-                       if ((cpu_amd_range[i].model & modelflag) &&
-                           (cpu_amd_range[i].flag & flag))
-                               return 1;
-                       break;
-               }
+       for (i = 0; i < ARRAY_SIZE(cpu_reg_range); i++) {
+               if (cpu_reg_range[i].flag == flag)
+                       return 1;
        }
 
        /* Invalid */
@@ -385,26 +183,11 @@ static int is_typeflag_valid(unsigned cpu, unsigned flag)
 static unsigned get_cpu_range(unsigned cpu, unsigned *min, unsigned *max,
                              int index, unsigned flag)
 {
-       unsigned modelflag;
-
-       modelflag = per_cpu(cpu_modelflag, cpu);
-       *max = 0;
-       switch (per_cpu(cpu_model, cpu) >> 16) {
-       case X86_VENDOR_INTEL:
-               if ((cpu_intel_range[index].model & modelflag) &&
-                   (cpu_intel_range[index].flag & flag)) {
-                       *min = cpu_intel_range[index].min;
-                       *max = cpu_intel_range[index].max;
-               }
-               break;
-       case X86_VENDOR_AMD:
-               if ((cpu_amd_range[index].model & modelflag) &&
-                   (cpu_amd_range[index].flag & flag)) {
-                       *min = cpu_amd_range[index].min;
-                       *max = cpu_amd_range[index].max;
-               }
-               break;
-       }
+       if (cpu_reg_range[index].flag == flag) {
+               *min = cpu_reg_range[index].min;
+               *max = cpu_reg_range[index].max;
+       } else
+               *max = 0;
 
        return *max;
 }
@@ -434,7 +217,7 @@ static void print_msr(struct seq_file *seq, unsigned cpu, unsigned flag)
        unsigned msr, msr_min, msr_max;
        struct cpu_private *priv;
        u32 low, high;
-       int i, range;
+       int i;
 
        if (seq) {
                priv = seq->private;
@@ -446,9 +229,7 @@ static void print_msr(struct seq_file *seq, unsigned cpu, unsigned flag)
                }
        }
 
-       range = get_cpu_range_count(cpu);
-
-       for (i = 0; i < range; i++) {
+       for (i = 0; i < ARRAY_SIZE(cpu_reg_range); i++) {
                if (!get_cpu_range(cpu, &msr_min, &msr_max, i, flag))
                        continue;
 
@@ -588,8 +369,20 @@ static void print_apic(void *arg)
        seq_printf(seq, " TMICT\t\t: %08x\n",  apic_read(APIC_TMICT));
        seq_printf(seq, " TMCCT\t\t: %08x\n",  apic_read(APIC_TMCCT));
        seq_printf(seq, " TDCR\t\t: %08x\n",  apic_read(APIC_TDCR));
-#endif /* CONFIG_X86_LOCAL_APIC */
+       if (boot_cpu_has(X86_FEATURE_EXTAPIC)) {
+               unsigned int i, v, maxeilvt;
+
+               v = apic_read(APIC_EFEAT);
+               maxeilvt = (v >> 16) & 0xff;
+               seq_printf(seq, " EFEAT\t\t: %08x\n", v);
+               seq_printf(seq, " ECTRL\t\t: %08x\n", apic_read(APIC_ECTRL));
 
+               for (i = 0; i < maxeilvt; i++) {
+                       v = apic_read(APIC_EILVTn(i));
+                       seq_printf(seq, " EILVT%d\t\t: %08x\n", i, v);
+               }
+       }
+#endif /* CONFIG_X86_LOCAL_APIC */
        seq_printf(seq, "\n MSR\t:\n");
 }
 
@@ -788,13 +581,11 @@ static int cpu_init_msr(unsigned cpu, unsigned type, struct dentry *dentry)
 {
        struct dentry *cpu_dentry = NULL;
        unsigned reg, reg_min, reg_max;
-       int i, range, err = 0;
+       int i, err = 0;
        char reg_dir[12];
        u32 low, high;
 
-       range = get_cpu_range_count(cpu);
-
-       for (i = 0; i < range; i++) {
+       for (i = 0; i < ARRAY_SIZE(cpu_reg_range); i++) {
                if (!get_cpu_range(cpu, &reg_min, &reg_max, i,
                                   cpu_base[type].flag))
                        continue;
@@ -850,10 +641,6 @@ static int cpu_init_cpu(void)
                cpui = &cpu_data(cpu);
                if (!cpu_has(cpui, X86_FEATURE_MSR))
                        continue;
-               per_cpu(cpu_model, cpu) = ((cpui->x86_vendor << 16) |
-                                          (cpui->x86 << 8) |
-                                          (cpui->x86_model));
-               per_cpu(cpu_modelflag, cpu) = get_cpu_modelflag(cpu);
 
                sprintf(cpu_dir, "cpu%d", cpu);
                cpu_dentry = debugfs_create_dir(cpu_dir, cpu_debugfs_dir);
index 52c839875478571711df3d861ffc1a3d4c5eb413..f138c6c389b921628575575f6a2b0c115441f6c0 100644 (file)
@@ -220,11 +220,14 @@ config X86_LONGHAUL
          If in doubt, say N.
 
 config X86_E_POWERSAVER
-       tristate "VIA C7 Enhanced PowerSaver"
+       tristate "VIA C7 Enhanced PowerSaver (DANGEROUS)"
        select CPU_FREQ_TABLE
-       depends on X86_32
+       depends on X86_32 && EXPERIMENTAL
        help
-         This adds the CPUFreq driver for VIA C7 processors.
+         This adds the CPUFreq driver for VIA C7 processors.  However, this driver
+         does not have any safeguards to prevent operating the CPU out of spec
+         and is thus considered dangerous.  Please use the regular ACPI cpufreq
+         driver, enabled by CONFIG_X86_ACPI_CPUFREQ.
 
          If in doubt, say N.
 
index 752e8c6b2c7e29e903895a4abe541b6e186b7add..ae9b503220cafa62e818afd4bfcf3b849a86c4b3 100644 (file)
@@ -90,11 +90,7 @@ static int check_est_cpu(unsigned int cpuid)
 {
        struct cpuinfo_x86 *cpu = &cpu_data(cpuid);
 
-       if (cpu->x86_vendor != X86_VENDOR_INTEL ||
-           !cpu_has(cpu, X86_FEATURE_EST))
-               return 0;
-
-       return 1;
+       return cpu_has(cpu, X86_FEATURE_EST);
 }
 
 static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
index 7437fa133c02dfdde137ca7201fb9734888a85bc..daed39ba2614dbcad31e4725b343d56d0912f05d 100644 (file)
@@ -229,12 +229,12 @@ static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
 }
 #endif
 
-static void __cpuinit srat_detect_node(void)
+static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c)
 {
 #if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
        unsigned node;
        int cpu = smp_processor_id();
-       int apicid = hard_smp_processor_id();
+       int apicid = cpu_has_apic ? hard_smp_processor_id() : c->apicid;
 
        /* Don't do the funky fallback heuristics the AMD version employs
           for now. */
@@ -400,7 +400,7 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
        }
 
        /* Work around errata */
-       srat_detect_node();
+       srat_detect_node(c);
 
        if (cpu_has(c, X86_FEATURE_VMX))
                detect_vmx_virtcap(c);
index 483eda96e102062b23f3e29820d911a9c7d6ab59..789efe217e1ab89a8862df2387a980d2cca9a60a 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <asm/processor.h>
 #include <asm/smp.h>
+#include <asm/k8.h>
 
 #define LVL_1_INST     1
 #define LVL_1_DATA     2
@@ -159,14 +160,6 @@ struct _cpuid4_info_regs {
        unsigned long can_disable;
 };
 
-#if defined(CONFIG_PCI) && defined(CONFIG_SYSFS)
-static struct pci_device_id k8_nb_id[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) },
-       { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1203) },
-       {}
-};
-#endif
-
 unsigned short                 num_cache_leaves;
 
 /* AMD doesn't have CPUID4. Emulate it here to report the same
@@ -207,10 +200,17 @@ union l3_cache {
 };
 
 static const unsigned short __cpuinitconst assocs[] = {
-       [1] = 1, [2] = 2, [4] = 4, [6] = 8,
-       [8] = 16, [0xa] = 32, [0xb] = 48,
+       [1] = 1,
+       [2] = 2,
+       [4] = 4,
+       [6] = 8,
+       [8] = 16,
+       [0xa] = 32,
+       [0xb] = 48,
        [0xc] = 64,
-       [0xf] = 0xffff // ??
+       [0xd] = 96,
+       [0xe] = 128,
+       [0xf] = 0xffff /* fully associative - no way to show this currently */
 };
 
 static const unsigned char __cpuinitconst levels[] = { 1, 1, 2, 3 };
@@ -271,7 +271,8 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
        eax->split.type = types[leaf];
        eax->split.level = levels[leaf];
        if (leaf == 3)
-               eax->split.num_threads_sharing = current_cpu_data.x86_max_cores - 1;
+               eax->split.num_threads_sharing =
+                       current_cpu_data.x86_max_cores - 1;
        else
                eax->split.num_threads_sharing = 0;
        eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
@@ -291,6 +292,14 @@ amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf)
 {
        if (index < 3)
                return;
+
+       if (boot_cpu_data.x86 == 0x11)
+               return;
+
+       /* see erratum #382 */
+       if ((boot_cpu_data.x86 == 0x10) && (boot_cpu_data.x86_model < 0x8))
+               return;
+
        this_leaf->can_disable = 1;
 }
 
@@ -696,97 +705,75 @@ static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf)
 #define to_object(k)   container_of(k, struct _index_kobject, kobj)
 #define to_attr(a)     container_of(a, struct _cache_attr, attr)
 
-#ifdef CONFIG_PCI
-static struct pci_dev *get_k8_northbridge(int node)
-{
-       struct pci_dev *dev = NULL;
-       int i;
-
-       for (i = 0; i <= node; i++) {
-               do {
-                       dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
-                       if (!dev)
-                               break;
-               } while (!pci_match_id(&k8_nb_id[0], dev));
-               if (!dev)
-                       break;
-       }
-       return dev;
-}
-#else
-static struct pci_dev *get_k8_northbridge(int node)
-{
-       return NULL;
-}
-#endif
-
-static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf)
+static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
+                                 unsigned int index)
 {
-       const struct cpumask *mask = to_cpumask(this_leaf->shared_cpu_map);
-       int node = cpu_to_node(cpumask_first(mask));
-       struct pci_dev *dev = NULL;
-       ssize_t ret = 0;
-       int i;
+       int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map));
+       int node = cpu_to_node(cpu);
+       struct pci_dev *dev = node_to_k8_nb_misc(node);
+       unsigned int reg = 0;
 
        if (!this_leaf->can_disable)
-               return sprintf(buf, "Feature not enabled\n");
-
-       dev = get_k8_northbridge(node);
-       if (!dev) {
-               printk(KERN_ERR "Attempting AMD northbridge operation on a system with no northbridge\n");
                return -EINVAL;
-       }
 
-       for (i = 0; i < 2; i++) {
-               unsigned int reg;
+       if (!dev)
+               return -EINVAL;
 
-               pci_read_config_dword(dev, 0x1BC + i * 4, &reg);
+       pci_read_config_dword(dev, 0x1BC + index * 4, &reg);
+       return sprintf(buf, "%x\n", reg);
+}
 
-               ret += sprintf(buf, "%sEntry: %d\n", buf, i);
-               ret += sprintf(buf, "%sReads:  %s\tNew Entries: %s\n",  
-                       buf,
-                       reg & 0x80000000 ? "Disabled" : "Allowed",
-                       reg & 0x40000000 ? "Disabled" : "Allowed");
-               ret += sprintf(buf, "%sSubCache: %x\tIndex: %x\n",
-                       buf, (reg & 0x30000) >> 16, reg & 0xfff);
-       }
-       return ret;
+#define SHOW_CACHE_DISABLE(index)                                      \
+static ssize_t                                                         \
+show_cache_disable_##index(struct _cpuid4_info *this_leaf, char *buf)          \
+{                                                                      \
+       return show_cache_disable(this_leaf, buf, index);               \
 }
+SHOW_CACHE_DISABLE(0)
+SHOW_CACHE_DISABLE(1)
 
-static ssize_t
-store_cache_disable(struct _cpuid4_info *this_leaf, const char *buf,
-                   size_t count)
+static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
+       const char *buf, size_t count, unsigned int index)
 {
-       const struct cpumask *mask = to_cpumask(this_leaf->shared_cpu_map);
-       int node = cpu_to_node(cpumask_first(mask));
-       struct pci_dev *dev = NULL;
-       unsigned int ret, index, val;
+       int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map));
+       int node = cpu_to_node(cpu);
+       struct pci_dev *dev = node_to_k8_nb_misc(node);
+       unsigned long val = 0;
+       unsigned int scrubber = 0;
 
        if (!this_leaf->can_disable)
-               return 0;
-
-       if (strlen(buf) > 15)
                return -EINVAL;
 
-       ret = sscanf(buf, "%x %x", &index, &val);
-       if (ret != 2)
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (!dev)
                return -EINVAL;
-       if (index > 1)
+
+       if (strict_strtoul(buf, 10, &val) < 0)
                return -EINVAL;
 
        val |= 0xc0000000;
-       dev = get_k8_northbridge(node);
-       if (!dev) {
-               printk(KERN_ERR "Attempting AMD northbridge operation on a system with no northbridge\n");
-               return -EINVAL;
-       }
+
+       pci_read_config_dword(dev, 0x58, &scrubber);
+       scrubber &= ~0x1f000000;
+       pci_write_config_dword(dev, 0x58, scrubber);
 
        pci_write_config_dword(dev, 0x1BC + index * 4, val & ~0x40000000);
        wbinvd();
        pci_write_config_dword(dev, 0x1BC + index * 4, val);
+       return count;
+}
 
-       return 1;
+#define STORE_CACHE_DISABLE(index)                                     \
+static ssize_t                                                         \
+store_cache_disable_##index(struct _cpuid4_info *this_leaf,            \
+                           const char *buf, size_t count)              \
+{                                                                      \
+       return store_cache_disable(this_leaf, buf, count, index);       \
 }
+STORE_CACHE_DISABLE(0)
+STORE_CACHE_DISABLE(1)
 
 struct _cache_attr {
        struct attribute attr;
@@ -808,7 +795,10 @@ define_one_ro(size);
 define_one_ro(shared_cpu_map);
 define_one_ro(shared_cpu_list);
 
-static struct _cache_attr cache_disable = __ATTR(cache_disable, 0644, show_cache_disable, store_cache_disable);
+static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644,
+               show_cache_disable_0, store_cache_disable_0);
+static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644,
+               show_cache_disable_1, store_cache_disable_1);
 
 static struct attribute * default_attrs[] = {
        &type.attr,
@@ -820,7 +810,8 @@ static struct attribute * default_attrs[] = {
        &size.attr,
        &shared_cpu_map.attr,
        &shared_cpu_list.attr,
-       &cache_disable.attr,
+       &cache_disable_0.attr,
+       &cache_disable_1.attr,
        NULL
 };
 
index 09dd1d414fc36bf40eb8218619298e76bf1ac443..289cc481502887dd228161157002b297e4a5a73d 100644 (file)
@@ -420,6 +420,7 @@ void do_machine_check(struct pt_regs * regs, long error_code)
  out2:
        atomic_dec(&mce_entry);
 }
+EXPORT_SYMBOL_GPL(do_machine_check);
 
 #ifdef CONFIG_X86_MCE_INTEL
 /***
index cef3ee30744b9964c9503f1ffd137c7d5c9aaf69..65a0fceedcd77ce7ed0088a5b24b0432caebd990 100644 (file)
@@ -15,7 +15,6 @@
 #include <asm/hw_irq.h>
 #include <asm/idle.h>
 #include <asm/therm_throt.h>
-#include <asm/apic.h>
 
 asmlinkage void smp_thermal_interrupt(void)
 {
index ce0fe4b5c04f6cfef4c14109124d55bd13f90cbe..1d584a18a50dab20fbe35e21e10859db05f2fe39 100644 (file)
@@ -808,7 +808,7 @@ int __init mtrr_cleanup(unsigned address_bits)
 
        if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1)
                return 0;
-       rdmsr(MTRRdefType_MSR, def, dummy);
+       rdmsr(MSR_MTRRdefType, def, dummy);
        def &= 0xff;
        if (def != MTRR_TYPE_UNCACHABLE)
                return 0;
@@ -1003,7 +1003,7 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
         */
        if (!is_cpu(INTEL) || disable_mtrr_trim)
                return 0;
-       rdmsr(MTRRdefType_MSR, def, dummy);
+       rdmsr(MSR_MTRRdefType, def, dummy);
        def &= 0xff;
        if (def != MTRR_TYPE_UNCACHABLE)
                return 0;
index d21d4fb161f70f43e91d229e94706567fbf3954e..0543f69f0b270c4ec6a4edf9f603df9f8228b0ea 100644 (file)
@@ -20,9 +20,9 @@ struct fixed_range_block {
 };
 
 static struct fixed_range_block fixed_range_blocks[] = {
-       { MTRRfix64K_00000_MSR, 1 }, /* one  64k MTRR  */
-       { MTRRfix16K_80000_MSR, 2 }, /* two  16k MTRRs */
-       { MTRRfix4K_C0000_MSR,  8 }, /* eight 4k MTRRs */
+       { MSR_MTRRfix64K_00000, 1 }, /* one  64k MTRR  */
+       { MSR_MTRRfix16K_80000, 2 }, /* two  16k MTRRs */
+       { MSR_MTRRfix4K_C0000,  8 }, /* eight 4k MTRRs */
        {}
 };
 
@@ -194,12 +194,12 @@ get_fixed_ranges(mtrr_type * frs)
 
        k8_check_syscfg_dram_mod_en();
 
-       rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
+       rdmsr(MSR_MTRRfix64K_00000, p[0], p[1]);
 
        for (i = 0; i < 2; i++)
-               rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2], p[3 + i * 2]);
+               rdmsr(MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]);
        for (i = 0; i < 8; i++)
-               rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]);
+               rdmsr(MSR_MTRRfix4K_C0000 + i, p[6 + i * 2], p[7 + i * 2]);
 }
 
 void mtrr_save_fixed_ranges(void *info)
@@ -310,7 +310,7 @@ void __init get_mtrr_state(void)
 
        vrs = mtrr_state.var_ranges;
 
-       rdmsr(MTRRcap_MSR, lo, dummy);
+       rdmsr(MSR_MTRRcap, lo, dummy);
        mtrr_state.have_fixed = (lo >> 8) & 1;
 
        for (i = 0; i < num_var_ranges; i++)
@@ -318,7 +318,7 @@ void __init get_mtrr_state(void)
        if (mtrr_state.have_fixed)
                get_fixed_ranges(mtrr_state.fixed_ranges);
 
-       rdmsr(MTRRdefType_MSR, lo, dummy);
+       rdmsr(MSR_MTRRdefType, lo, dummy);
        mtrr_state.def_type = (lo & 0xff);
        mtrr_state.enabled = (lo & 0xc00) >> 10;
 
@@ -583,10 +583,10 @@ static void prepare_set(void) __acquires(set_atomicity_lock)
        __flush_tlb();
 
        /*  Save MTRR state */
-       rdmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
+       rdmsr(MSR_MTRRdefType, deftype_lo, deftype_hi);
 
        /*  Disable MTRRs, and set the default type to uncached  */
-       mtrr_wrmsr(MTRRdefType_MSR, deftype_lo & ~0xcff, deftype_hi);
+       mtrr_wrmsr(MSR_MTRRdefType, deftype_lo & ~0xcff, deftype_hi);
 }
 
 static void post_set(void) __releases(set_atomicity_lock)
@@ -595,7 +595,7 @@ static void post_set(void) __releases(set_atomicity_lock)
        __flush_tlb();
 
        /* Intel (P6) standard MTRRs */
-       mtrr_wrmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
+       mtrr_wrmsr(MSR_MTRRdefType, deftype_lo, deftype_hi);
                
        /*  Enable caches  */
        write_cr0(read_cr0() & 0xbfffffff);
@@ -707,7 +707,7 @@ int generic_validate_add_page(unsigned long base, unsigned long size, unsigned i
 static int generic_have_wrcomb(void)
 {
        unsigned long config, dummy;
-       rdmsr(MTRRcap_MSR, config, dummy);
+       rdmsr(MSR_MTRRcap, config, dummy);
        return (config & (1 << 10));
 }
 
index 03cda01f57c7125173a8b348d92105d5bcd5dd28..8fc248b5aeafe26a0f822350bf9488685b9eab4e 100644 (file)
@@ -104,7 +104,7 @@ static void __init set_num_var_ranges(void)
        unsigned long config = 0, dummy;
 
        if (use_intel()) {
-               rdmsr(MTRRcap_MSR, config, dummy);
+               rdmsr(MSR_MTRRcap, config, dummy);
        } else if (is_cpu(AMD))
                config = 2;
        else if (is_cpu(CYRIX) || is_cpu(CENTAUR))
index 77f67f7b347a3a97a093b1094c5da86a2ca9ad35..7538b767f2060ed4727bb992f665b87e629b1bc5 100644 (file)
@@ -5,21 +5,6 @@
 #include <linux/types.h>
 #include <linux/stddef.h>
 
-#define MTRRcap_MSR     0x0fe
-#define MTRRdefType_MSR 0x2ff
-
-#define MTRRfix64K_00000_MSR 0x250
-#define MTRRfix16K_80000_MSR 0x258
-#define MTRRfix16K_A0000_MSR 0x259
-#define MTRRfix4K_C0000_MSR 0x268
-#define MTRRfix4K_C8000_MSR 0x269
-#define MTRRfix4K_D0000_MSR 0x26a
-#define MTRRfix4K_D8000_MSR 0x26b
-#define MTRRfix4K_E0000_MSR 0x26c
-#define MTRRfix4K_E8000_MSR 0x26d
-#define MTRRfix4K_F0000_MSR 0x26e
-#define MTRRfix4K_F8000_MSR 0x26f
-
 #define MTRR_CHANGE_MASK_FIXED     0x01
 #define MTRR_CHANGE_MASK_VARIABLE  0x02
 #define MTRR_CHANGE_MASK_DEFTYPE   0x04
index 7f7e2753685bce875ccd6dca8903474e366456cc..1f5fb1588d1fb4df0bbaefc4196b23a6056140aa 100644 (file)
@@ -35,7 +35,7 @@ void set_mtrr_prepare_save(struct set_mtrr_context *ctxt)
 
                if (use_intel())
                        /*  Save MTRR state */
-                       rdmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+                       rdmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi);
                else
                        /* Cyrix ARRs - everything else were excluded at the top */
                        ctxt->ccr3 = getCx86(CX86_CCR3);
@@ -46,7 +46,7 @@ void set_mtrr_cache_disable(struct set_mtrr_context *ctxt)
 {
        if (use_intel())
                /*  Disable MTRRs, and set the default type to uncached  */
-               mtrr_wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL,
+               mtrr_wrmsr(MSR_MTRRdefType, ctxt->deftype_lo & 0xf300UL,
                      ctxt->deftype_hi);
        else if (is_cpu(CYRIX))
                /* Cyrix ARRs - everything else were excluded at the top */
@@ -64,7 +64,7 @@ void set_mtrr_done(struct set_mtrr_context *ctxt)
                /*  Restore MTRRdefType  */
                if (use_intel())
                        /* Intel (P6) standard MTRRs */
-                       mtrr_wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+                       mtrr_wrmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi);
                else
                        /* Cyrix ARRs - everything else was excluded at the top */
                        setCx86(CX86_CCR3, ctxt->ccr3);
index 87b67e3a765ac212c2c954de3566ec487fdac8da..48bfe1386038c91fc9ee5b99473e67df5a93a432 100644 (file)
  * Markus Metzger <markus.t.metzger@intel.com>, 2007-2009
  */
 
-
-#include <asm/ds.h>
-
-#include <linux/errno.h>
+#include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/slab.h>
+#include <linux/errno.h>
 #include <linux/sched.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/kernel.h>
+#include <linux/trace_clock.h>
+
+#include <asm/ds.h>
 
+#include "ds_selftest.h"
 
 /*
- * The configuration for a particular DS hardware implementation.
+ * The configuration for a particular DS hardware implementation:
  */
 struct ds_configuration {
-       /* the name of the configuration */
-       const char *name;
-       /* the size of one pointer-typed field in the DS structure and
-          in the BTS and PEBS buffers in bytes;
-          this covers the first 8 DS fields related to buffer management. */
-       unsigned char  sizeof_field;
-       /* the size of a BTS/PEBS record in bytes */
-       unsigned char  sizeof_rec[2];
-       /* a series of bit-masks to control various features indexed
-        * by enum ds_feature */
-       unsigned long ctl[dsf_ctl_max];
+       /* The name of the configuration: */
+       const char              *name;
+
+       /* The size of pointer-typed fields in DS, BTS, and PEBS: */
+       unsigned char           sizeof_ptr_field;
+
+       /* The size of a BTS/PEBS record in bytes: */
+       unsigned char           sizeof_rec[2];
+
+       /* The number of pebs counter reset values in the DS structure. */
+       unsigned char           nr_counter_reset;
+
+       /* Control bit-masks indexed by enum ds_feature: */
+       unsigned long           ctl[dsf_ctl_max];
 };
-static DEFINE_PER_CPU(struct ds_configuration, ds_cfg_array);
+static struct ds_configuration ds_cfg __read_mostly;
+
+
+/* Maximal size of a DS configuration: */
+#define MAX_SIZEOF_DS          0x80
 
-#define ds_cfg per_cpu(ds_cfg_array, smp_processor_id())
+/* Maximal size of a BTS record: */
+#define MAX_SIZEOF_BTS         (3 * 8)
 
-#define MAX_SIZEOF_DS (12 * 8) /* maximal size of a DS configuration */
-#define MAX_SIZEOF_BTS (3 * 8) /* maximal size of a BTS record */
-#define DS_ALIGNMENT (1 << 3)  /* BTS and PEBS buffer alignment */
+/* BTS and PEBS buffer alignment: */
+#define DS_ALIGNMENT           (1 << 3)
 
-#define BTS_CONTROL \
- (ds_cfg.ctl[dsf_bts] | ds_cfg.ctl[dsf_bts_kernel] | ds_cfg.ctl[dsf_bts_user] |\
-  ds_cfg.ctl[dsf_bts_overflow])
+/* Number of buffer pointers in DS: */
+#define NUM_DS_PTR_FIELDS      8
 
+/* Size of a pebs reset value in DS: */
+#define PEBS_RESET_FIELD_SIZE  8
+
+/* Mask of control bits in the DS MSR register: */
+#define BTS_CONTROL                              \
+       ( ds_cfg.ctl[dsf_bts]                   | \
+         ds_cfg.ctl[dsf_bts_kernel]            | \
+         ds_cfg.ctl[dsf_bts_user]              | \
+         ds_cfg.ctl[dsf_bts_overflow] )
 
 /*
  * A BTS or PEBS tracer.
@@ -66,29 +82,36 @@ static DEFINE_PER_CPU(struct ds_configuration, ds_cfg_array);
  * to identify tracers.
  */
 struct ds_tracer {
-       /* the DS context (partially) owned by this tracer */
-       struct ds_context *context;
-       /* the buffer provided on ds_request() and its size in bytes */
-       void *buffer;
-       size_t size;
+       /* The DS context (partially) owned by this tracer. */
+       struct ds_context       *context;
+       /* The buffer provided on ds_request() and its size in bytes. */
+       void                    *buffer;
+       size_t                  size;
 };
 
 struct bts_tracer {
-       /* the common DS part */
-       struct ds_tracer ds;
-       /* the trace including the DS configuration */
-       struct bts_trace trace;
-       /* buffer overflow notification function */
-       bts_ovfl_callback_t ovfl;
+       /* The common DS part: */
+       struct ds_tracer        ds;
+
+       /* The trace including the DS configuration: */
+       struct bts_trace        trace;
+
+       /* Buffer overflow notification function: */
+       bts_ovfl_callback_t     ovfl;
+
+       /* Active flags affecting trace collection. */
+       unsigned int            flags;
 };
 
 struct pebs_tracer {
-       /* the common DS part */
-       struct ds_tracer ds;
-       /* the trace including the DS configuration */
-       struct pebs_trace trace;
-       /* buffer overflow notification function */
-       pebs_ovfl_callback_t ovfl;
+       /* The common DS part: */
+       struct ds_tracer        ds;
+
+       /* The trace including the DS configuration: */
+       struct pebs_trace       trace;
+
+       /* Buffer overflow notification function: */
+       pebs_ovfl_callback_t    ovfl;
 };
 
 /*
@@ -97,6 +120,7 @@ struct pebs_tracer {
  *
  * The DS configuration consists of the following fields; different
  * architetures vary in the size of those fields.
+ *
  * - double-word aligned base linear address of the BTS buffer
  * - write pointer into the BTS buffer
  * - end linear address of the BTS buffer (one byte beyond the end of
@@ -135,21 +159,22 @@ enum ds_field {
 };
 
 enum ds_qualifier {
-       ds_bts  = 0,
+       ds_bts = 0,
        ds_pebs
 };
 
-static inline unsigned long ds_get(const unsigned char *base,
-                                  enum ds_qualifier qual, enum ds_field field)
+static inline unsigned long
+ds_get(const unsigned char *base, enum ds_qualifier qual, enum ds_field field)
 {
-       base += (ds_cfg.sizeof_field * (field + (4 * qual)));
+       base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual)));
        return *(unsigned long *)base;
 }
 
-static inline void ds_set(unsigned char *base, enum ds_qualifier qual,
-                         enum ds_field field, unsigned long value)
+static inline void
+ds_set(unsigned char *base, enum ds_qualifier qual, enum ds_field field,
+       unsigned long value)
 {
-       base += (ds_cfg.sizeof_field * (field + (4 * qual)));
+       base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual)));
        (*(unsigned long *)base) = value;
 }
 
@@ -159,7 +184,6 @@ static inline void ds_set(unsigned char *base, enum ds_qualifier qual,
  */
 static DEFINE_SPINLOCK(ds_lock);
 
-
 /*
  * We either support (system-wide) per-cpu or per-thread allocation.
  * We distinguish the two based on the task_struct pointer, where a
@@ -178,12 +202,28 @@ static DEFINE_SPINLOCK(ds_lock);
  */
 static atomic_t tracers = ATOMIC_INIT(0);
 
-static inline void get_tracer(struct task_struct *task)
+static inline int get_tracer(struct task_struct *task)
 {
-       if (task)
+       int error;
+
+       spin_lock_irq(&ds_lock);
+
+       if (task) {
+               error = -EPERM;
+               if (atomic_read(&tracers) < 0)
+                       goto out;
                atomic_inc(&tracers);
-       else
+       } else {
+               error = -EPERM;
+               if (atomic_read(&tracers) > 0)
+                       goto out;
                atomic_dec(&tracers);
+       }
+
+       error = 0;
+out:
+       spin_unlock_irq(&ds_lock);
+       return error;
 }
 
 static inline void put_tracer(struct task_struct *task)
@@ -194,14 +234,6 @@ static inline void put_tracer(struct task_struct *task)
                atomic_inc(&tracers);
 }
 
-static inline int check_tracer(struct task_struct *task)
-{
-       return task ?
-               (atomic_read(&tracers) >= 0) :
-               (atomic_read(&tracers) <= 0);
-}
-
-
 /*
  * The DS context is either attached to a thread or to a cpu:
  * - in the former case, the thread_struct contains a pointer to the
@@ -213,61 +245,58 @@ static inline int check_tracer(struct task_struct *task)
  * deallocated when the last user puts the context.
  */
 struct ds_context {
-       /* pointer to the DS configuration; goes into MSR_IA32_DS_AREA */
-       unsigned char ds[MAX_SIZEOF_DS];
-       /* the owner of the BTS and PEBS configuration, respectively */
-       struct bts_tracer *bts_master;
-       struct pebs_tracer *pebs_master;
-       /* use count */
-       unsigned long count;
-       /* a pointer to the context location inside the thread_struct
-        * or the per_cpu context array */
-       struct ds_context **this;
-       /* a pointer to the task owning this context, or NULL, if the
-        * context is owned by a cpu */
-       struct task_struct *task;
-};
+       /* The DS configuration; goes into MSR_IA32_DS_AREA: */
+       unsigned char           ds[MAX_SIZEOF_DS];
+
+       /* The owner of the BTS and PEBS configuration, respectively: */
+       struct bts_tracer       *bts_master;
+       struct pebs_tracer      *pebs_master;
 
-static DEFINE_PER_CPU(struct ds_context *, system_context_array);
+       /* Use count: */
+       unsigned long           count;
 
-#define system_context per_cpu(system_context_array, smp_processor_id())
+       /* Pointer to the context pointer field: */
+       struct ds_context       **this;
+
+       /* The traced task; NULL for cpu tracing: */
+       struct task_struct      *task;
+
+       /* The traced cpu; only valid if task is NULL: */
+       int                     cpu;
+};
 
+static DEFINE_PER_CPU(struct ds_context *, cpu_context);
 
-static inline struct ds_context *ds_get_context(struct task_struct *task)
+
+static struct ds_context *ds_get_context(struct task_struct *task, int cpu)
 {
        struct ds_context **p_context =
-               (task ? &task->thread.ds_ctx : &system_context);
+               (task ? &task->thread.ds_ctx : &per_cpu(cpu_context, cpu));
        struct ds_context *context = NULL;
        struct ds_context *new_context = NULL;
-       unsigned long irq;
 
        /* Chances are small that we already have a context. */
        new_context = kzalloc(sizeof(*new_context), GFP_KERNEL);
        if (!new_context)
                return NULL;
 
-       spin_lock_irqsave(&ds_lock, irq);
+       spin_lock_irq(&ds_lock);
 
        context = *p_context;
-       if (!context) {
+       if (likely(!context)) {
                context = new_context;
 
                context->this = p_context;
                context->task = task;
+               context->cpu = cpu;
                context->count = 0;
 
-               if (task)
-                       set_tsk_thread_flag(task, TIF_DS_AREA_MSR);
-
-               if (!task || (task == current))
-                       wrmsrl(MSR_IA32_DS_AREA, (unsigned long)context->ds);
-
                *p_context = context;
        }
 
        context->count++;
 
-       spin_unlock_irqrestore(&ds_lock, irq);
+       spin_unlock_irq(&ds_lock);
 
        if (context != new_context)
                kfree(new_context);
@@ -275,8 +304,9 @@ static inline struct ds_context *ds_get_context(struct task_struct *task)
        return context;
 }
 
-static inline void ds_put_context(struct ds_context *context)
+static void ds_put_context(struct ds_context *context)
 {
+       struct task_struct *task;
        unsigned long irq;
 
        if (!context)
@@ -291,17 +321,55 @@ static inline void ds_put_context(struct ds_context *context)
 
        *(context->this) = NULL;
 
-       if (context->task)
-               clear_tsk_thread_flag(context->task, TIF_DS_AREA_MSR);
+       task = context->task;
+
+       if (task)
+               clear_tsk_thread_flag(task, TIF_DS_AREA_MSR);
 
-       if (!context->task || (context->task == current))
-               wrmsrl(MSR_IA32_DS_AREA, 0);
+       /*
+        * We leave the (now dangling) pointer to the DS configuration in
+        * the DS_AREA msr. This is as good or as bad as replacing it with
+        * NULL - the hardware would crash if we enabled tracing.
+        *
+        * This saves us some problems with having to write an msr on a
+        * different cpu while preventing others from doing the same for the
+        * next context for that same cpu.
+        */
 
        spin_unlock_irqrestore(&ds_lock, irq);
 
+       /* The context might still be in use for context switching. */
+       if (task && (task != current))
+               wait_task_context_switch(task);
+
        kfree(context);
 }
 
+static void ds_install_ds_area(struct ds_context *context)
+{
+       unsigned long ds;
+
+       ds = (unsigned long)context->ds;
+
+       /*
+        * There is a race between the bts master and the pebs master.
+        *
+        * The thread/cpu access is synchronized via get/put_cpu() for
+        * task tracing and via wrmsr_on_cpu for cpu tracing.
+        *
+        * If bts and pebs are collected for the same task or same cpu,
+        * the same confiuration is written twice.
+        */
+       if (context->task) {
+               get_cpu();
+               if (context->task == current)
+                       wrmsrl(MSR_IA32_DS_AREA, ds);
+               set_tsk_thread_flag(context->task, TIF_DS_AREA_MSR);
+               put_cpu();
+       } else
+               wrmsr_on_cpu(context->cpu, MSR_IA32_DS_AREA,
+                            (u32)((u64)ds), (u32)((u64)ds >> 32));
+}
 
 /*
  * Call the tracer's callback on a buffer overflow.
@@ -332,9 +400,9 @@ static void ds_overflow(struct ds_context *context, enum ds_qualifier qual)
  * The remainder of any partially written record is zeroed out.
  *
  * context: the DS context
- * qual: the buffer type
- * record: the data to write
- * size: the size of the data
+ * qual:    the buffer type
+ * record:  the data to write
+ * size:    the size of the data
  */
 static int ds_write(struct ds_context *context, enum ds_qualifier qual,
                    const void *record, size_t size)
@@ -349,14 +417,14 @@ static int ds_write(struct ds_context *context, enum ds_qualifier qual,
                unsigned long write_size, adj_write_size;
 
                /*
-                * write as much as possible without producing an
+                * Write as much as possible without producing an
                 * overflow interrupt.
                 *
-                * interrupt_threshold must either be
+                * Interrupt_threshold must either be
                 * - bigger than absolute_maximum or
                 * - point to a record between buffer_base and absolute_maximum
                 *
-                * index points to a valid record.
+                * Index points to a valid record.
                 */
                base   = ds_get(context->ds, qual, ds_buffer_base);
                index  = ds_get(context->ds, qual, ds_index);
@@ -365,8 +433,10 @@ static int ds_write(struct ds_context *context, enum ds_qualifier qual,
 
                write_end = min(end, int_th);
 
-               /* if we are already beyond the interrupt threshold,
-                * we fill the entire buffer */
+               /*
+                * If we are already beyond the interrupt threshold,
+                * we fill the entire buffer.
+                */
                if (write_end <= index)
                        write_end = end;
 
@@ -383,7 +453,7 @@ static int ds_write(struct ds_context *context, enum ds_qualifier qual,
                adj_write_size = write_size / ds_cfg.sizeof_rec[qual];
                adj_write_size *= ds_cfg.sizeof_rec[qual];
 
-               /* zero out trailing bytes */
+               /* Zero out trailing bytes. */
                memset((char *)index + write_size, 0,
                       adj_write_size - write_size);
                index += adj_write_size;
@@ -410,7 +480,7 @@ static int ds_write(struct ds_context *context, enum ds_qualifier qual,
  * Later architectures use 64bit pointers throughout, whereas earlier
  * architectures use 32bit pointers in 32bit mode.
  *
- * We compute the base address for the first 8 fields based on:
+ * We compute the base address for the fields based on:
  * - the field size stored in the DS configuration
  * - the relative field position
  *
@@ -431,23 +501,23 @@ enum bts_field {
        bts_to,
        bts_flags,
 
-       bts_qual = bts_from,
-       bts_jiffies = bts_to,
-       bts_pid = bts_flags,
+       bts_qual                = bts_from,
+       bts_clock               = bts_to,
+       bts_pid                 = bts_flags,
 
-       bts_qual_mask = (bts_qual_max - 1),
-       bts_escape = ((unsigned long)-1 & ~bts_qual_mask)
+       bts_qual_mask           = (bts_qual_max - 1),
+       bts_escape              = ((unsigned long)-1 & ~bts_qual_mask)
 };
 
 static inline unsigned long bts_get(const char *base, enum bts_field field)
 {
-       base += (ds_cfg.sizeof_field * field);
+       base += (ds_cfg.sizeof_ptr_field * field);
        return *(unsigned long *)base;
 }
 
 static inline void bts_set(char *base, enum bts_field field, unsigned long val)
 {
-       base += (ds_cfg.sizeof_field * field);;
+       base += (ds_cfg.sizeof_ptr_field * field);;
        (*(unsigned long *)base) = val;
 }
 
@@ -463,8 +533,8 @@ static inline void bts_set(char *base, enum bts_field field, unsigned long val)
  *
  * return: bytes read/written on success; -Eerrno, otherwise
  */
-static int bts_read(struct bts_tracer *tracer, const void *at,
-                   struct bts_struct *out)
+static int
+bts_read(struct bts_tracer *tracer, const void *at, struct bts_struct *out)
 {
        if (!tracer)
                return -EINVAL;
@@ -478,8 +548,8 @@ static int bts_read(struct bts_tracer *tracer, const void *at,
        memset(out, 0, sizeof(*out));
        if ((bts_get(at, bts_qual) & ~bts_qual_mask) == bts_escape) {
                out->qualifier = (bts_get(at, bts_qual) & bts_qual_mask);
-               out->variant.timestamp.jiffies = bts_get(at, bts_jiffies);
-               out->variant.timestamp.pid = bts_get(at, bts_pid);
+               out->variant.event.clock = bts_get(at, bts_clock);
+               out->variant.event.pid = bts_get(at, bts_pid);
        } else {
                out->qualifier = bts_branch;
                out->variant.lbr.from = bts_get(at, bts_from);
@@ -516,8 +586,8 @@ static int bts_write(struct bts_tracer *tracer, const struct bts_struct *in)
        case bts_task_arrives:
        case bts_task_departs:
                bts_set(raw, bts_qual, (bts_escape | in->qualifier));
-               bts_set(raw, bts_jiffies, in->variant.timestamp.jiffies);
-               bts_set(raw, bts_pid, in->variant.timestamp.pid);
+               bts_set(raw, bts_clock, in->variant.event.clock);
+               bts_set(raw, bts_pid, in->variant.event.pid);
                break;
        default:
                return -EINVAL;
@@ -555,7 +625,8 @@ static void ds_init_ds_trace(struct ds_trace *trace, enum ds_qualifier qual,
                             unsigned int flags) {
        unsigned long buffer, adj;
 
-       /* adjust the buffer address and size to meet alignment
+       /*
+        * Adjust the buffer address and size to meet alignment
         * constraints:
         * - buffer is double-word aligned
         * - size is multiple of record size
@@ -577,9 +648,11 @@ static void ds_init_ds_trace(struct ds_trace *trace, enum ds_qualifier qual,
        trace->begin = (void *)buffer;
        trace->top = trace->begin;
        trace->end = (void *)(buffer + size);
-       /* The value for 'no threshold' is -1, which will set the
+       /*
+        * The value for 'no threshold' is -1, which will set the
         * threshold outside of the buffer, just like we want it.
         */
+       ith *= ds_cfg.sizeof_rec[qual];
        trace->ith = (void *)(buffer + size - ith);
 
        trace->flags = flags;
@@ -588,18 +661,27 @@ static void ds_init_ds_trace(struct ds_trace *trace, enum ds_qualifier qual,
 
 static int ds_request(struct ds_tracer *tracer, struct ds_trace *trace,
                      enum ds_qualifier qual, struct task_struct *task,
-                     void *base, size_t size, size_t th, unsigned int flags)
+                     int cpu, void *base, size_t size, size_t th)
 {
        struct ds_context *context;
        int error;
+       size_t req_size;
+
+       error = -EOPNOTSUPP;
+       if (!ds_cfg.sizeof_rec[qual])
+               goto out;
 
        error = -EINVAL;
        if (!base)
                goto out;
 
-       /* we require some space to do alignment adjustments below */
+       req_size = ds_cfg.sizeof_rec[qual];
+       /* We might need space for alignment adjustments. */
+       if (!IS_ALIGNED((unsigned long)base, DS_ALIGNMENT))
+               req_size += DS_ALIGNMENT;
+
        error = -EINVAL;
-       if (size < (DS_ALIGNMENT + ds_cfg.sizeof_rec[qual]))
+       if (size < req_size)
                goto out;
 
        if (th != (size_t)-1) {
@@ -614,182 +696,318 @@ static int ds_request(struct ds_tracer *tracer, struct ds_trace *trace,
        tracer->size = size;
 
        error = -ENOMEM;
-       context = ds_get_context(task);
+       context = ds_get_context(task, cpu);
        if (!context)
                goto out;
        tracer->context = context;
 
-       ds_init_ds_trace(trace, qual, base, size, th, flags);
+       /*
+        * Defer any tracer-specific initialization work for the context until
+        * context ownership has been clarified.
+        */
 
        error = 0;
  out:
        return error;
 }
 
-struct bts_tracer *ds_request_bts(struct task_struct *task,
-                                 void *base, size_t size,
-                                 bts_ovfl_callback_t ovfl, size_t th,
-                                 unsigned int flags)
+static struct bts_tracer *ds_request_bts(struct task_struct *task, int cpu,
+                                        void *base, size_t size,
+                                        bts_ovfl_callback_t ovfl, size_t th,
+                                        unsigned int flags)
 {
        struct bts_tracer *tracer;
-       unsigned long irq;
        int error;
 
+       /* Buffer overflow notification is not yet implemented. */
        error = -EOPNOTSUPP;
-       if (!ds_cfg.ctl[dsf_bts])
+       if (ovfl)
                goto out;
 
-       /* buffer overflow notification is not yet implemented */
-       error = -EOPNOTSUPP;
-       if (ovfl)
+       error = get_tracer(task);
+       if (error < 0)
                goto out;
 
        error = -ENOMEM;
        tracer = kzalloc(sizeof(*tracer), GFP_KERNEL);
        if (!tracer)
-               goto out;
+               goto out_put_tracer;
        tracer->ovfl = ovfl;
 
+       /* Do some more error checking and acquire a tracing context. */
        error = ds_request(&tracer->ds, &tracer->trace.ds,
-                          ds_bts, task, base, size, th, flags);
+                          ds_bts, task, cpu, base, size, th);
        if (error < 0)
                goto out_tracer;
 
-
-       spin_lock_irqsave(&ds_lock, irq);
-
-       error = -EPERM;
-       if (!check_tracer(task))
-               goto out_unlock;
-       get_tracer(task);
+       /* Claim the bts part of the tracing context we acquired above. */
+       spin_lock_irq(&ds_lock);
 
        error = -EPERM;
        if (tracer->ds.context->bts_master)
-               goto out_put_tracer;
+               goto out_unlock;
        tracer->ds.context->bts_master = tracer;
 
-       spin_unlock_irqrestore(&ds_lock, irq);
+       spin_unlock_irq(&ds_lock);
 
+       /*
+        * Now that we own the bts part of the context, let's complete the
+        * initialization for that part.
+        */
+       ds_init_ds_trace(&tracer->trace.ds, ds_bts, base, size, th, flags);
+       ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_bts);
+       ds_install_ds_area(tracer->ds.context);
 
        tracer->trace.read  = bts_read;
        tracer->trace.write = bts_write;
 
-       ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_bts);
+       /* Start tracing. */
        ds_resume_bts(tracer);
 
        return tracer;
 
- out_put_tracer:
-       put_tracer(task);
  out_unlock:
-       spin_unlock_irqrestore(&ds_lock, irq);
+       spin_unlock_irq(&ds_lock);
        ds_put_context(tracer->ds.context);
  out_tracer:
        kfree(tracer);
+ out_put_tracer:
+       put_tracer(task);
  out:
        return ERR_PTR(error);
 }
 
-struct pebs_tracer *ds_request_pebs(struct task_struct *task,
-                                   void *base, size_t size,
-                                   pebs_ovfl_callback_t ovfl, size_t th,
-                                   unsigned int flags)
+struct bts_tracer *ds_request_bts_task(struct task_struct *task,
+                                      void *base, size_t size,
+                                      bts_ovfl_callback_t ovfl,
+                                      size_t th, unsigned int flags)
+{
+       return ds_request_bts(task, 0, base, size, ovfl, th, flags);
+}
+
+struct bts_tracer *ds_request_bts_cpu(int cpu, void *base, size_t size,
+                                     bts_ovfl_callback_t ovfl,
+                                     size_t th, unsigned int flags)
+{
+       return ds_request_bts(NULL, cpu, base, size, ovfl, th, flags);
+}
+
+static struct pebs_tracer *ds_request_pebs(struct task_struct *task, int cpu,
+                                          void *base, size_t size,
+                                          pebs_ovfl_callback_t ovfl, size_t th,
+                                          unsigned int flags)
 {
        struct pebs_tracer *tracer;
-       unsigned long irq;
        int error;
 
-       /* buffer overflow notification is not yet implemented */
+       /* Buffer overflow notification is not yet implemented. */
        error = -EOPNOTSUPP;
        if (ovfl)
                goto out;
 
+       error = get_tracer(task);
+       if (error < 0)
+               goto out;
+
        error = -ENOMEM;
        tracer = kzalloc(sizeof(*tracer), GFP_KERNEL);
        if (!tracer)
-               goto out;
+               goto out_put_tracer;
        tracer->ovfl = ovfl;
 
+       /* Do some more error checking and acquire a tracing context. */
        error = ds_request(&tracer->ds, &tracer->trace.ds,
-                          ds_pebs, task, base, size, th, flags);
+                          ds_pebs, task, cpu, base, size, th);
        if (error < 0)
                goto out_tracer;
 
-       spin_lock_irqsave(&ds_lock, irq);
-
-       error = -EPERM;
-       if (!check_tracer(task))
-               goto out_unlock;
-       get_tracer(task);
+       /* Claim the pebs part of the tracing context we acquired above. */
+       spin_lock_irq(&ds_lock);
 
        error = -EPERM;
        if (tracer->ds.context->pebs_master)
-               goto out_put_tracer;
+               goto out_unlock;
        tracer->ds.context->pebs_master = tracer;
 
-       spin_unlock_irqrestore(&ds_lock, irq);
+       spin_unlock_irq(&ds_lock);
 
+       /*
+        * Now that we own the pebs part of the context, let's complete the
+        * initialization for that part.
+        */
+       ds_init_ds_trace(&tracer->trace.ds, ds_pebs, base, size, th, flags);
        ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_pebs);
+       ds_install_ds_area(tracer->ds.context);
+
+       /* Start tracing. */
        ds_resume_pebs(tracer);
 
        return tracer;
 
- out_put_tracer:
-       put_tracer(task);
  out_unlock:
-       spin_unlock_irqrestore(&ds_lock, irq);
+       spin_unlock_irq(&ds_lock);
        ds_put_context(tracer->ds.context);
  out_tracer:
        kfree(tracer);
+ out_put_tracer:
+       put_tracer(task);
  out:
        return ERR_PTR(error);
 }
 
-void ds_release_bts(struct bts_tracer *tracer)
+struct pebs_tracer *ds_request_pebs_task(struct task_struct *task,
+                                        void *base, size_t size,
+                                        pebs_ovfl_callback_t ovfl,
+                                        size_t th, unsigned int flags)
 {
-       if (!tracer)
-               return;
+       return ds_request_pebs(task, 0, base, size, ovfl, th, flags);
+}
 
-       ds_suspend_bts(tracer);
+struct pebs_tracer *ds_request_pebs_cpu(int cpu, void *base, size_t size,
+                                       pebs_ovfl_callback_t ovfl,
+                                       size_t th, unsigned int flags)
+{
+       return ds_request_pebs(NULL, cpu, base, size, ovfl, th, flags);
+}
+
+static void ds_free_bts(struct bts_tracer *tracer)
+{
+       struct task_struct *task;
+
+       task = tracer->ds.context->task;
 
        WARN_ON_ONCE(tracer->ds.context->bts_master != tracer);
        tracer->ds.context->bts_master = NULL;
 
-       put_tracer(tracer->ds.context->task);
+       /* Make sure tracing stopped and the tracer is not in use. */
+       if (task && (task != current))
+               wait_task_context_switch(task);
+
        ds_put_context(tracer->ds.context);
+       put_tracer(task);
 
        kfree(tracer);
 }
 
+void ds_release_bts(struct bts_tracer *tracer)
+{
+       might_sleep();
+
+       if (!tracer)
+               return;
+
+       ds_suspend_bts(tracer);
+       ds_free_bts(tracer);
+}
+
+int ds_release_bts_noirq(struct bts_tracer *tracer)
+{
+       struct task_struct *task;
+       unsigned long irq;
+       int error;
+
+       if (!tracer)
+               return 0;
+
+       task = tracer->ds.context->task;
+
+       local_irq_save(irq);
+
+       error = -EPERM;
+       if (!task &&
+           (tracer->ds.context->cpu != smp_processor_id()))
+               goto out;
+
+       error = -EPERM;
+       if (task && (task != current))
+               goto out;
+
+       ds_suspend_bts_noirq(tracer);
+       ds_free_bts(tracer);
+
+       error = 0;
+ out:
+       local_irq_restore(irq);
+       return error;
+}
+
+static void update_task_debugctlmsr(struct task_struct *task,
+                                   unsigned long debugctlmsr)
+{
+       task->thread.debugctlmsr = debugctlmsr;
+
+       get_cpu();
+       if (task == current)
+               update_debugctlmsr(debugctlmsr);
+       put_cpu();
+}
+
 void ds_suspend_bts(struct bts_tracer *tracer)
 {
        struct task_struct *task;
+       unsigned long debugctlmsr;
+       int cpu;
 
        if (!tracer)
                return;
 
+       tracer->flags = 0;
+
        task = tracer->ds.context->task;
+       cpu  = tracer->ds.context->cpu;
 
-       if (!task || (task == current))
-               update_debugctlmsr(get_debugctlmsr() & ~BTS_CONTROL);
+       WARN_ON(!task && irqs_disabled());
 
-       if (task) {
-               task->thread.debugctlmsr &= ~BTS_CONTROL;
+       debugctlmsr = (task ?
+                      task->thread.debugctlmsr :
+                      get_debugctlmsr_on_cpu(cpu));
+       debugctlmsr &= ~BTS_CONTROL;
 
-               if (!task->thread.debugctlmsr)
-                       clear_tsk_thread_flag(task, TIF_DEBUGCTLMSR);
-       }
+       if (task)
+               update_task_debugctlmsr(task, debugctlmsr);
+       else
+               update_debugctlmsr_on_cpu(cpu, debugctlmsr);
 }
 
-void ds_resume_bts(struct bts_tracer *tracer)
+int ds_suspend_bts_noirq(struct bts_tracer *tracer)
 {
        struct task_struct *task;
-       unsigned long control;
+       unsigned long debugctlmsr, irq;
+       int cpu, error = 0;
 
        if (!tracer)
-               return;
+               return 0;
+
+       tracer->flags = 0;
 
        task = tracer->ds.context->task;
+       cpu  = tracer->ds.context->cpu;
+
+       local_irq_save(irq);
+
+       error = -EPERM;
+       if (!task && (cpu != smp_processor_id()))
+               goto out;
+
+       debugctlmsr = (task ?
+                      task->thread.debugctlmsr :
+                      get_debugctlmsr());
+       debugctlmsr &= ~BTS_CONTROL;
+
+       if (task)
+               update_task_debugctlmsr(task, debugctlmsr);
+       else
+               update_debugctlmsr(debugctlmsr);
+
+       error = 0;
+ out:
+       local_irq_restore(irq);
+       return error;
+}
+
+static unsigned long ds_bts_control(struct bts_tracer *tracer)
+{
+       unsigned long control;
 
        control = ds_cfg.ctl[dsf_bts];
        if (!(tracer->trace.ds.flags & BTS_KERNEL))
@@ -797,41 +1015,149 @@ void ds_resume_bts(struct bts_tracer *tracer)
        if (!(tracer->trace.ds.flags & BTS_USER))
                control |= ds_cfg.ctl[dsf_bts_user];
 
-       if (task) {
-               task->thread.debugctlmsr |= control;
-               set_tsk_thread_flag(task, TIF_DEBUGCTLMSR);
-       }
-
-       if (!task || (task == current))
-               update_debugctlmsr(get_debugctlmsr() | control);
+       return control;
 }
 
-void ds_release_pebs(struct pebs_tracer *tracer)
+void ds_resume_bts(struct bts_tracer *tracer)
 {
+       struct task_struct *task;
+       unsigned long debugctlmsr;
+       int cpu;
+
        if (!tracer)
                return;
 
-       ds_suspend_pebs(tracer);
+       tracer->flags = tracer->trace.ds.flags;
+
+       task = tracer->ds.context->task;
+       cpu  = tracer->ds.context->cpu;
+
+       WARN_ON(!task && irqs_disabled());
+
+       debugctlmsr = (task ?
+                      task->thread.debugctlmsr :
+                      get_debugctlmsr_on_cpu(cpu));
+       debugctlmsr |= ds_bts_control(tracer);
+
+       if (task)
+               update_task_debugctlmsr(task, debugctlmsr);
+       else
+               update_debugctlmsr_on_cpu(cpu, debugctlmsr);
+}
+
+int ds_resume_bts_noirq(struct bts_tracer *tracer)
+{
+       struct task_struct *task;
+       unsigned long debugctlmsr, irq;
+       int cpu, error = 0;
+
+       if (!tracer)
+               return 0;
+
+       tracer->flags = tracer->trace.ds.flags;
+
+       task = tracer->ds.context->task;
+       cpu  = tracer->ds.context->cpu;
+
+       local_irq_save(irq);
+
+       error = -EPERM;
+       if (!task && (cpu != smp_processor_id()))
+               goto out;
+
+       debugctlmsr = (task ?
+                      task->thread.debugctlmsr :
+                      get_debugctlmsr());
+       debugctlmsr |= ds_bts_control(tracer);
+
+       if (task)
+               update_task_debugctlmsr(task, debugctlmsr);
+       else
+               update_debugctlmsr(debugctlmsr);
+
+       error = 0;
+ out:
+       local_irq_restore(irq);
+       return error;
+}
+
+static void ds_free_pebs(struct pebs_tracer *tracer)
+{
+       struct task_struct *task;
+
+       task = tracer->ds.context->task;
 
        WARN_ON_ONCE(tracer->ds.context->pebs_master != tracer);
        tracer->ds.context->pebs_master = NULL;
 
-       put_tracer(tracer->ds.context->task);
        ds_put_context(tracer->ds.context);
+       put_tracer(task);
 
        kfree(tracer);
 }
 
+void ds_release_pebs(struct pebs_tracer *tracer)
+{
+       might_sleep();
+
+       if (!tracer)
+               return;
+
+       ds_suspend_pebs(tracer);
+       ds_free_pebs(tracer);
+}
+
+int ds_release_pebs_noirq(struct pebs_tracer *tracer)
+{
+       struct task_struct *task;
+       unsigned long irq;
+       int error;
+
+       if (!tracer)
+               return 0;
+
+       task = tracer->ds.context->task;
+
+       local_irq_save(irq);
+
+       error = -EPERM;
+       if (!task &&
+           (tracer->ds.context->cpu != smp_processor_id()))
+               goto out;
+
+       error = -EPERM;
+       if (task && (task != current))
+               goto out;
+
+       ds_suspend_pebs_noirq(tracer);
+       ds_free_pebs(tracer);
+
+       error = 0;
+ out:
+       local_irq_restore(irq);
+       return error;
+}
+
 void ds_suspend_pebs(struct pebs_tracer *tracer)
 {
 
 }
 
+int ds_suspend_pebs_noirq(struct pebs_tracer *tracer)
+{
+       return 0;
+}
+
 void ds_resume_pebs(struct pebs_tracer *tracer)
 {
 
 }
 
+int ds_resume_pebs_noirq(struct pebs_tracer *tracer)
+{
+       return 0;
+}
+
 const struct bts_trace *ds_read_bts(struct bts_tracer *tracer)
 {
        if (!tracer)
@@ -847,8 +1173,12 @@ const struct pebs_trace *ds_read_pebs(struct pebs_tracer *tracer)
                return NULL;
 
        ds_read_config(tracer->ds.context, &tracer->trace.ds, ds_pebs);
-       tracer->trace.reset_value =
-               *(u64 *)(tracer->ds.context->ds + (ds_cfg.sizeof_field * 8));
+
+       tracer->trace.counters = ds_cfg.nr_counter_reset;
+       memcpy(tracer->trace.counter_reset,
+              tracer->ds.context->ds +
+              (NUM_DS_PTR_FIELDS * ds_cfg.sizeof_ptr_field),
+              ds_cfg.nr_counter_reset * PEBS_RESET_FIELD_SIZE);
 
        return &tracer->trace;
 }
@@ -873,18 +1203,24 @@ int ds_reset_pebs(struct pebs_tracer *tracer)
 
        tracer->trace.ds.top = tracer->trace.ds.begin;
 
-       ds_set(tracer->ds.context->ds, ds_bts, ds_index,
+       ds_set(tracer->ds.context->ds, ds_pebs, ds_index,
               (unsigned long)tracer->trace.ds.top);
 
        return 0;
 }
 
-int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value)
+int ds_set_pebs_reset(struct pebs_tracer *tracer,
+                     unsigned int counter, u64 value)
 {
        if (!tracer)
                return -EINVAL;
 
-       *(u64 *)(tracer->ds.context->ds + (ds_cfg.sizeof_field * 8)) = value;
+       if (ds_cfg.nr_counter_reset < counter)
+               return -EINVAL;
+
+       *(u64 *)(tracer->ds.context->ds +
+                (NUM_DS_PTR_FIELDS * ds_cfg.sizeof_ptr_field) +
+                (counter * PEBS_RESET_FIELD_SIZE)) = value;
 
        return 0;
 }
@@ -894,73 +1230,117 @@ static const struct ds_configuration ds_cfg_netburst = {
        .ctl[dsf_bts]           = (1 << 2) | (1 << 3),
        .ctl[dsf_bts_kernel]    = (1 << 5),
        .ctl[dsf_bts_user]      = (1 << 6),
-
-       .sizeof_field           = sizeof(long),
-       .sizeof_rec[ds_bts]     = sizeof(long) * 3,
-#ifdef __i386__
-       .sizeof_rec[ds_pebs]    = sizeof(long) * 10,
-#else
-       .sizeof_rec[ds_pebs]    = sizeof(long) * 18,
-#endif
+       .nr_counter_reset       = 1,
 };
 static const struct ds_configuration ds_cfg_pentium_m = {
        .name = "Pentium M",
        .ctl[dsf_bts]           = (1 << 6) | (1 << 7),
-
-       .sizeof_field           = sizeof(long),
-       .sizeof_rec[ds_bts]     = sizeof(long) * 3,
-#ifdef __i386__
-       .sizeof_rec[ds_pebs]    = sizeof(long) * 10,
-#else
-       .sizeof_rec[ds_pebs]    = sizeof(long) * 18,
-#endif
+       .nr_counter_reset       = 1,
 };
 static const struct ds_configuration ds_cfg_core2_atom = {
        .name = "Core 2/Atom",
        .ctl[dsf_bts]           = (1 << 6) | (1 << 7),
        .ctl[dsf_bts_kernel]    = (1 << 9),
        .ctl[dsf_bts_user]      = (1 << 10),
-
-       .sizeof_field           = 8,
-       .sizeof_rec[ds_bts]     = 8 * 3,
-       .sizeof_rec[ds_pebs]    = 8 * 18,
+       .nr_counter_reset       = 1,
+};
+static const struct ds_configuration ds_cfg_core_i7 = {
+       .name = "Core i7",
+       .ctl[dsf_bts]           = (1 << 6) | (1 << 7),
+       .ctl[dsf_bts_kernel]    = (1 << 9),
+       .ctl[dsf_bts_user]      = (1 << 10),
+       .nr_counter_reset       = 4,
 };
 
 static void
-ds_configure(const struct ds_configuration *cfg)
+ds_configure(const struct ds_configuration *cfg,
+            struct cpuinfo_x86 *cpu)
 {
+       unsigned long nr_pebs_fields = 0;
+
+       printk(KERN_INFO "[ds] using %s configuration\n", cfg->name);
+
+#ifdef __i386__
+       nr_pebs_fields = 10;
+#else
+       nr_pebs_fields = 18;
+#endif
+
+       /*
+        * Starting with version 2, architectural performance
+        * monitoring supports a format specifier.
+        */
+       if ((cpuid_eax(0xa) & 0xff) > 1) {
+               unsigned long perf_capabilities, format;
+
+               rdmsrl(MSR_IA32_PERF_CAPABILITIES, perf_capabilities);
+
+               format = (perf_capabilities >> 8) & 0xf;
+
+               switch (format) {
+               case 0:
+                       nr_pebs_fields = 18;
+                       break;
+               case 1:
+                       nr_pebs_fields = 22;
+                       break;
+               default:
+                       printk(KERN_INFO
+                              "[ds] unknown PEBS format: %lu\n", format);
+                       nr_pebs_fields = 0;
+                       break;
+               }
+       }
+
        memset(&ds_cfg, 0, sizeof(ds_cfg));
        ds_cfg = *cfg;
 
-       printk(KERN_INFO "[ds] using %s configuration\n", ds_cfg.name);
+       ds_cfg.sizeof_ptr_field =
+               (cpu_has(cpu, X86_FEATURE_DTES64) ? 8 : 4);
+
+       ds_cfg.sizeof_rec[ds_bts]  = ds_cfg.sizeof_ptr_field * 3;
+       ds_cfg.sizeof_rec[ds_pebs] = ds_cfg.sizeof_ptr_field * nr_pebs_fields;
 
-       if (!cpu_has_bts) {
-               ds_cfg.ctl[dsf_bts] = 0;
+       if (!cpu_has(cpu, X86_FEATURE_BTS)) {
+               ds_cfg.sizeof_rec[ds_bts] = 0;
                printk(KERN_INFO "[ds] bts not available\n");
        }
-       if (!cpu_has_pebs)
+       if (!cpu_has(cpu, X86_FEATURE_PEBS)) {
+               ds_cfg.sizeof_rec[ds_pebs] = 0;
                printk(KERN_INFO "[ds] pebs not available\n");
+       }
+
+       printk(KERN_INFO "[ds] sizes: address: %u bit, ",
+              8 * ds_cfg.sizeof_ptr_field);
+       printk("bts/pebs record: %u/%u bytes\n",
+              ds_cfg.sizeof_rec[ds_bts], ds_cfg.sizeof_rec[ds_pebs]);
 
-       WARN_ON_ONCE(MAX_SIZEOF_DS < (12 * ds_cfg.sizeof_field));
+       WARN_ON_ONCE(MAX_PEBS_COUNTERS < ds_cfg.nr_counter_reset);
 }
 
 void __cpuinit ds_init_intel(struct cpuinfo_x86 *c)
 {
+       /* Only configure the first cpu. Others are identical. */
+       if (ds_cfg.name)
+               return;
+
        switch (c->x86) {
        case 0x6:
                switch (c->x86_model) {
                case 0x9:
                case 0xd: /* Pentium M */
-                       ds_configure(&ds_cfg_pentium_m);
+                       ds_configure(&ds_cfg_pentium_m, c);
                        break;
                case 0xf:
                case 0x17: /* Core2 */
                case 0x1c: /* Atom */
-                       ds_configure(&ds_cfg_core2_atom);
+                       ds_configure(&ds_cfg_core2_atom, c);
+                       break;
+               case 0x1a: /* Core i7 */
+                       ds_configure(&ds_cfg_core_i7, c);
                        break;
-               case 0x1a: /* i7 */
                default:
-                       /* sorry, don't know about them */
+                       /* Sorry, don't know about them. */
                        break;
                }
                break;
@@ -969,64 +1349,89 @@ void __cpuinit ds_init_intel(struct cpuinfo_x86 *c)
                case 0x0:
                case 0x1:
                case 0x2: /* Netburst */
-                       ds_configure(&ds_cfg_netburst);
+                       ds_configure(&ds_cfg_netburst, c);
                        break;
                default:
-                       /* sorry, don't know about them */
+                       /* Sorry, don't know about them. */
                        break;
                }
                break;
        default:
-               /* sorry, don't know about them */
+               /* Sorry, don't know about them. */
                break;
        }
 }
 
+static inline void ds_take_timestamp(struct ds_context *context,
+                                    enum bts_qualifier qualifier,
+                                    struct task_struct *task)
+{
+       struct bts_tracer *tracer = context->bts_master;
+       struct bts_struct ts;
+
+       /* Prevent compilers from reading the tracer pointer twice. */
+       barrier();
+
+       if (!tracer || !(tracer->flags & BTS_TIMESTAMPS))
+               return;
+
+       memset(&ts, 0, sizeof(ts));
+       ts.qualifier            = qualifier;
+       ts.variant.event.clock  = trace_clock_global();
+       ts.variant.event.pid    = task->pid;
+
+       bts_write(tracer, &ts);
+}
+
 /*
  * Change the DS configuration from tracing prev to tracing next.
  */
 void ds_switch_to(struct task_struct *prev, struct task_struct *next)
 {
-       struct ds_context *prev_ctx = prev->thread.ds_ctx;
-       struct ds_context *next_ctx = next->thread.ds_ctx;
+       struct ds_context *prev_ctx     = prev->thread.ds_ctx;
+       struct ds_context *next_ctx     = next->thread.ds_ctx;
+       unsigned long debugctlmsr       = next->thread.debugctlmsr;
+
+       /* Make sure all data is read before we start. */
+       barrier();
 
        if (prev_ctx) {
                update_debugctlmsr(0);
 
-               if (prev_ctx->bts_master &&
-                   (prev_ctx->bts_master->trace.ds.flags & BTS_TIMESTAMPS)) {
-                       struct bts_struct ts = {
-                               .qualifier = bts_task_departs,
-                               .variant.timestamp.jiffies = jiffies_64,
-                               .variant.timestamp.pid = prev->pid
-                       };
-                       bts_write(prev_ctx->bts_master, &ts);
-               }
+               ds_take_timestamp(prev_ctx, bts_task_departs, prev);
        }
 
        if (next_ctx) {
-               if (next_ctx->bts_master &&
-                   (next_ctx->bts_master->trace.ds.flags & BTS_TIMESTAMPS)) {
-                       struct bts_struct ts = {
-                               .qualifier = bts_task_arrives,
-                               .variant.timestamp.jiffies = jiffies_64,
-                               .variant.timestamp.pid = next->pid
-                       };
-                       bts_write(next_ctx->bts_master, &ts);
-               }
+               ds_take_timestamp(next_ctx, bts_task_arrives, next);
 
                wrmsrl(MSR_IA32_DS_AREA, (unsigned long)next_ctx->ds);
        }
 
-       update_debugctlmsr(next->thread.debugctlmsr);
+       update_debugctlmsr(debugctlmsr);
 }
 
-void ds_copy_thread(struct task_struct *tsk, struct task_struct *father)
+static __init int ds_selftest(void)
 {
-       clear_tsk_thread_flag(tsk, TIF_DS_AREA_MSR);
-       tsk->thread.ds_ctx = NULL;
-}
+       if (ds_cfg.sizeof_rec[ds_bts]) {
+               int error;
 
-void ds_exit_thread(struct task_struct *tsk)
-{
+               error = ds_selftest_bts();
+               if (error) {
+                       WARN(1, "[ds] selftest failed. disabling bts.\n");
+                       ds_cfg.sizeof_rec[ds_bts] = 0;
+               }
+       }
+
+       if (ds_cfg.sizeof_rec[ds_pebs]) {
+               int error;
+
+               error = ds_selftest_pebs();
+               if (error) {
+                       WARN(1, "[ds] selftest failed. disabling pebs.\n");
+                       ds_cfg.sizeof_rec[ds_pebs] = 0;
+               }
+       }
+
+       return 0;
 }
+device_initcall(ds_selftest);
diff --git a/arch/x86/kernel/ds_selftest.c b/arch/x86/kernel/ds_selftest.c
new file mode 100644 (file)
index 0000000..6bc7c19
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * Debug Store support - selftest
+ *
+ *
+ * Copyright (C) 2009 Intel Corporation.
+ * Markus Metzger <markus.t.metzger@intel.com>, 2009
+ */
+
+#include "ds_selftest.h"
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+
+#include <asm/ds.h>
+
+
+#define BUFFER_SIZE            521     /* Intentionally chose an odd size. */
+#define SMALL_BUFFER_SIZE      24      /* A single bts entry. */
+
+struct ds_selftest_bts_conf {
+       struct bts_tracer *tracer;
+       int error;
+       int (*suspend)(struct bts_tracer *);
+       int (*resume)(struct bts_tracer *);
+};
+
+static int ds_selftest_bts_consistency(const struct bts_trace *trace)
+{
+       int error = 0;
+
+       if (!trace) {
+               printk(KERN_CONT "failed to access trace...");
+               /* Bail out. Other tests are pointless. */
+               return -1;
+       }
+
+       if (!trace->read) {
+               printk(KERN_CONT "bts read not available...");
+               error = -1;
+       }
+
+       /* Do some sanity checks on the trace configuration. */
+       if (!trace->ds.n) {
+               printk(KERN_CONT "empty bts buffer...");
+               error = -1;
+       }
+       if (!trace->ds.size) {
+               printk(KERN_CONT "bad bts trace setup...");
+               error = -1;
+       }
+       if (trace->ds.end !=
+           (char *)trace->ds.begin + (trace->ds.n * trace->ds.size)) {
+               printk(KERN_CONT "bad bts buffer setup...");
+               error = -1;
+       }
+       /*
+        * We allow top in [begin; end], since its not clear when the
+        * overflow adjustment happens: after the increment or before the
+        * write.
+        */
+       if ((trace->ds.top < trace->ds.begin) ||
+           (trace->ds.end < trace->ds.top)) {
+               printk(KERN_CONT "bts top out of bounds...");
+               error = -1;
+       }
+
+       return error;
+}
+
+static int ds_selftest_bts_read(struct bts_tracer *tracer,
+                               const struct bts_trace *trace,
+                               const void *from, const void *to)
+{
+       const unsigned char *at;
+
+       /*
+        * Check a few things which do not belong to this test.
+        * They should be covered by other tests.
+        */
+       if (!trace)
+               return -1;
+
+       if (!trace->read)
+               return -1;
+
+       if (to < from)
+               return -1;
+
+       if (from < trace->ds.begin)
+               return -1;
+
+       if (trace->ds.end < to)
+               return -1;
+
+       if (!trace->ds.size)
+               return -1;
+
+       /* Now to the test itself. */
+       for (at = from; (void *)at < to; at += trace->ds.size) {
+               struct bts_struct bts;
+               unsigned long index;
+               int error;
+
+               if (((void *)at - trace->ds.begin) % trace->ds.size) {
+                       printk(KERN_CONT
+                              "read from non-integer index...");
+                       return -1;
+               }
+               index = ((void *)at - trace->ds.begin) / trace->ds.size;
+
+               memset(&bts, 0, sizeof(bts));
+               error = trace->read(tracer, at, &bts);
+               if (error < 0) {
+                       printk(KERN_CONT
+                              "error reading bts trace at [%lu] (0x%p)...",
+                              index, at);
+                       return error;
+               }
+
+               switch (bts.qualifier) {
+               case BTS_BRANCH:
+                       break;
+               default:
+                       printk(KERN_CONT
+                              "unexpected bts entry %llu at [%lu] (0x%p)...",
+                              bts.qualifier, index, at);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static void ds_selftest_bts_cpu(void *arg)
+{
+       struct ds_selftest_bts_conf *conf = arg;
+       const struct bts_trace *trace;
+       void *top;
+
+       if (IS_ERR(conf->tracer)) {
+               conf->error = PTR_ERR(conf->tracer);
+               conf->tracer = NULL;
+
+               printk(KERN_CONT
+                      "initialization failed (err: %d)...", conf->error);
+               return;
+       }
+
+       /* We should meanwhile have enough trace. */
+       conf->error = conf->suspend(conf->tracer);
+       if (conf->error < 0)
+               return;
+
+       /* Let's see if we can access the trace. */
+       trace = ds_read_bts(conf->tracer);
+
+       conf->error = ds_selftest_bts_consistency(trace);
+       if (conf->error < 0)
+               return;
+
+       /* If everything went well, we should have a few trace entries. */
+       if (trace->ds.top == trace->ds.begin) {
+               /*
+                * It is possible but highly unlikely that we got a
+                * buffer overflow and end up at exactly the same
+                * position we started from.
+                * Let's issue a warning, but continue.
+                */
+               printk(KERN_CONT "no trace/overflow...");
+       }
+
+       /* Let's try to read the trace we collected. */
+       conf->error =
+               ds_selftest_bts_read(conf->tracer, trace,
+                                    trace->ds.begin, trace->ds.top);
+       if (conf->error < 0)
+               return;
+
+       /*
+        * Let's read the trace again.
+        * Since we suspended tracing, we should get the same result.
+        */
+       top = trace->ds.top;
+
+       trace = ds_read_bts(conf->tracer);
+       conf->error = ds_selftest_bts_consistency(trace);
+       if (conf->error < 0)
+               return;
+
+       if (top != trace->ds.top) {
+               printk(KERN_CONT "suspend not working...");
+               conf->error = -1;
+               return;
+       }
+
+       /* Let's collect some more trace - see if resume is working. */
+       conf->error = conf->resume(conf->tracer);
+       if (conf->error < 0)
+               return;
+
+       conf->error = conf->suspend(conf->tracer);
+       if (conf->error < 0)
+               return;
+
+       trace = ds_read_bts(conf->tracer);
+
+       conf->error = ds_selftest_bts_consistency(trace);
+       if (conf->error < 0)
+               return;
+
+       if (trace->ds.top == top) {
+               /*
+                * It is possible but highly unlikely that we got a
+                * buffer overflow and end up at exactly the same
+                * position we started from.
+                * Let's issue a warning and check the full trace.
+                */
+               printk(KERN_CONT
+                      "no resume progress/overflow...");
+
+               conf->error =
+                       ds_selftest_bts_read(conf->tracer, trace,
+                                            trace->ds.begin, trace->ds.end);
+       } else if (trace->ds.top < top) {
+               /*
+                * We had a buffer overflow - the entire buffer should
+                * contain trace records.
+                */
+               conf->error =
+                       ds_selftest_bts_read(conf->tracer, trace,
+                                            trace->ds.begin, trace->ds.end);
+       } else {
+               /*
+                * It is quite likely that the buffer did not overflow.
+                * Let's just check the delta trace.
+                */
+               conf->error =
+                       ds_selftest_bts_read(conf->tracer, trace, top,
+                                            trace->ds.top);
+       }
+       if (conf->error < 0)
+               return;
+
+       conf->error = 0;
+}
+
+static int ds_suspend_bts_wrap(struct bts_tracer *tracer)
+{
+       ds_suspend_bts(tracer);
+       return 0;
+}
+
+static int ds_resume_bts_wrap(struct bts_tracer *tracer)
+{
+       ds_resume_bts(tracer);
+       return 0;
+}
+
+static void ds_release_bts_noirq_wrap(void *tracer)
+{
+       (void)ds_release_bts_noirq(tracer);
+}
+
+static int ds_selftest_bts_bad_release_noirq(int cpu,
+                                            struct bts_tracer *tracer)
+{
+       int error = -EPERM;
+
+       /* Try to release the tracer on the wrong cpu. */
+       get_cpu();
+       if (cpu != smp_processor_id()) {
+               error = ds_release_bts_noirq(tracer);
+               if (error != -EPERM)
+                       printk(KERN_CONT "release on wrong cpu...");
+       }
+       put_cpu();
+
+       return error ? 0 : -1;
+}
+
+static int ds_selftest_bts_bad_request_cpu(int cpu, void *buffer)
+{
+       struct bts_tracer *tracer;
+       int error;
+
+       /* Try to request cpu tracing while task tracing is active. */
+       tracer = ds_request_bts_cpu(cpu, buffer, BUFFER_SIZE, NULL,
+                                   (size_t)-1, BTS_KERNEL);
+       error = PTR_ERR(tracer);
+       if (!IS_ERR(tracer)) {
+               ds_release_bts(tracer);
+               error = 0;
+       }
+
+       if (error != -EPERM)
+               printk(KERN_CONT "cpu/task tracing overlap...");
+
+       return error ? 0 : -1;
+}
+
+static int ds_selftest_bts_bad_request_task(void *buffer)
+{
+       struct bts_tracer *tracer;
+       int error;
+
+       /* Try to request cpu tracing while task tracing is active. */
+       tracer = ds_request_bts_task(current, buffer, BUFFER_SIZE, NULL,
+                                   (size_t)-1, BTS_KERNEL);
+       error = PTR_ERR(tracer);
+       if (!IS_ERR(tracer)) {
+               error = 0;
+               ds_release_bts(tracer);
+       }
+
+       if (error != -EPERM)
+               printk(KERN_CONT "task/cpu tracing overlap...");
+
+       return error ? 0 : -1;
+}
+
+int ds_selftest_bts(void)
+{
+       struct ds_selftest_bts_conf conf;
+       unsigned char buffer[BUFFER_SIZE], *small_buffer;
+       unsigned long irq;
+       int cpu;
+
+       printk(KERN_INFO "[ds] bts selftest...");
+       conf.error = 0;
+
+       small_buffer = (unsigned char *)ALIGN((unsigned long)buffer, 8) + 8;
+
+       get_online_cpus();
+       for_each_online_cpu(cpu) {
+               conf.suspend = ds_suspend_bts_wrap;
+               conf.resume = ds_resume_bts_wrap;
+               conf.tracer =
+                       ds_request_bts_cpu(cpu, buffer, BUFFER_SIZE,
+                                          NULL, (size_t)-1, BTS_KERNEL);
+               ds_selftest_bts_cpu(&conf);
+               if (conf.error >= 0)
+                       conf.error = ds_selftest_bts_bad_request_task(buffer);
+               ds_release_bts(conf.tracer);
+               if (conf.error < 0)
+                       goto out;
+
+               conf.suspend = ds_suspend_bts_noirq;
+               conf.resume = ds_resume_bts_noirq;
+               conf.tracer =
+                       ds_request_bts_cpu(cpu, buffer, BUFFER_SIZE,
+                                          NULL, (size_t)-1, BTS_KERNEL);
+               smp_call_function_single(cpu, ds_selftest_bts_cpu, &conf, 1);
+               if (conf.error >= 0) {
+                       conf.error =
+                               ds_selftest_bts_bad_release_noirq(cpu,
+                                                                 conf.tracer);
+                       /* We must not release the tracer twice. */
+                       if (conf.error < 0)
+                               conf.tracer = NULL;
+               }
+               if (conf.error >= 0)
+                       conf.error = ds_selftest_bts_bad_request_task(buffer);
+               smp_call_function_single(cpu, ds_release_bts_noirq_wrap,
+                                        conf.tracer, 1);
+               if (conf.error < 0)
+                       goto out;
+       }
+
+       conf.suspend = ds_suspend_bts_wrap;
+       conf.resume = ds_resume_bts_wrap;
+       conf.tracer =
+               ds_request_bts_task(current, buffer, BUFFER_SIZE,
+                                   NULL, (size_t)-1, BTS_KERNEL);
+       ds_selftest_bts_cpu(&conf);
+       if (conf.error >= 0)
+               conf.error = ds_selftest_bts_bad_request_cpu(0, buffer);
+       ds_release_bts(conf.tracer);
+       if (conf.error < 0)
+               goto out;
+
+       conf.suspend = ds_suspend_bts_noirq;
+       conf.resume = ds_resume_bts_noirq;
+       conf.tracer =
+               ds_request_bts_task(current, small_buffer, SMALL_BUFFER_SIZE,
+                                  NULL, (size_t)-1, BTS_KERNEL);
+       local_irq_save(irq);
+       ds_selftest_bts_cpu(&conf);
+       if (conf.error >= 0)
+               conf.error = ds_selftest_bts_bad_request_cpu(0, buffer);
+       ds_release_bts_noirq(conf.tracer);
+       local_irq_restore(irq);
+       if (conf.error < 0)
+               goto out;
+
+       conf.error = 0;
+ out:
+       put_online_cpus();
+       printk(KERN_CONT "%s.\n", (conf.error ? "failed" : "passed"));
+
+       return conf.error;
+}
+
+int ds_selftest_pebs(void)
+{
+       return 0;
+}
diff --git a/arch/x86/kernel/ds_selftest.h b/arch/x86/kernel/ds_selftest.h
new file mode 100644 (file)
index 0000000..2ba8745
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Debug Store support - selftest
+ *
+ *
+ * Copyright (C) 2009 Intel Corporation.
+ * Markus Metzger <markus.t.metzger@intel.com>, 2009
+ */
+
+#ifdef CONFIG_X86_DS_SELFTEST
+extern int ds_selftest_bts(void);
+extern int ds_selftest_pebs(void);
+#else
+static inline int ds_selftest_bts(void) { return 0; }
+static inline int ds_selftest_pebs(void) { return 0; }
+#endif
index da87590b8698a7c4642ad8e46febe2bf91972599..81086c227ab7cafe28c0c608f1b3eb2bce72b1c0 100644 (file)
@@ -29,7 +29,6 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
                unsigned long *sp, unsigned long bp, char *log_lvl);
 
 extern unsigned int code_bytes;
-extern int kstack_depth_to_print;
 
 /* The form of the top of the frame on the stack */
 struct stack_frame {
index 0062813029256a2379d4dc66c42741439227210e..7271fa33d79135edd790f854d7c0c91d05d0c20b 100644 (file)
@@ -617,7 +617,7 @@ __init int e820_search_gap(unsigned long *gapstart, unsigned long *gapsize,
  */
 __init void e820_setup_gap(void)
 {
-       unsigned long gapstart, gapsize, round;
+       unsigned long gapstart, gapsize;
        int found;
 
        gapstart = 0x10000000;
@@ -635,14 +635,9 @@ __init void e820_setup_gap(void)
 #endif
 
        /*
-        * See how much we want to round up: start off with
-        * rounding to the next 1MB area.
+        * e820_reserve_resources_late protect stolen RAM already
         */
-       round = 0x100000;
-       while ((gapsize >> 4) > round)
-               round += round;
-       /* Fun with two's complement */
-       pci_mem_start = (gapstart + round) & -round;
+       pci_mem_start = gapstart;
 
        printk(KERN_INFO
               "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n",
@@ -1371,6 +1366,23 @@ void __init e820_reserve_resources(void)
        }
 }
 
+/* How much should we pad RAM ending depending on where it is? */
+static unsigned long ram_alignment(resource_size_t pos)
+{
+       unsigned long mb = pos >> 20;
+
+       /* To 64kB in the first megabyte */
+       if (!mb)
+               return 64*1024;
+
+       /* To 1MB in the first 16MB */
+       if (mb < 16)
+               return 1024*1024;
+
+       /* To 32MB for anything above that */
+       return 32*1024*1024;
+}
+
 void __init e820_reserve_resources_late(void)
 {
        int i;
@@ -1382,6 +1394,24 @@ void __init e820_reserve_resources_late(void)
                        insert_resource_expand_to_fit(&iomem_resource, res);
                res++;
        }
+
+       /*
+        * Try to bump up RAM regions to reasonable boundaries to
+        * avoid stolen RAM:
+        */
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *entry = &e820_saved.map[i];
+               resource_size_t start, end;
+
+               if (entry->type != E820_RAM)
+                       continue;
+               start = entry->addr + entry->size;
+               end = round_up(start, ram_alignment(start));
+               if (start == end)
+                       continue;
+               reserve_region_with_split(&iomem_resource, start,
+                                                 end - 1, "RAM buffer");
+       }
 }
 
 char *__init default_machine_specific_memory_setup(void)
index 76b8cd953deed9f8a50d572cdc52b5edb68bc3b7..ebdb85cf2686fa36702cd4d50b657f22de85b3bd 100644 (file)
@@ -96,6 +96,7 @@ static void __init nvidia_bugs(int num, int slot, int func)
 
 }
 
+#if defined(CONFIG_ACPI) && defined(CONFIG_X86_IO_APIC)
 #if defined(CONFIG_ACPI) && defined(CONFIG_X86_IO_APIC)
 static u32 __init ati_ixp4x0_rev(int num, int slot, int func)
 {
@@ -114,6 +115,7 @@ static u32 __init ati_ixp4x0_rev(int num, int slot, int func)
        d &= 0xff;
        return d;
 }
+#endif
 
 static void __init ati_bugs(int num, int slot, int func)
 {
index 38946c6e843388b33fc165779bd7c0aec8e260d7..1c17d7c751a43762717f9e63eeff73b80843ca92 100644 (file)
@@ -147,27 +147,14 @@ END(ftrace_graph_caller)
 GLOBAL(return_to_handler)
        subq  $80, %rsp
 
+       /* Save the return values */
        movq %rax, (%rsp)
-       movq %rcx, 8(%rsp)
-       movq %rdx, 16(%rsp)
-       movq %rsi, 24(%rsp)
-       movq %rdi, 32(%rsp)
-       movq %r8, 40(%rsp)
-       movq %r9, 48(%rsp)
-       movq %r10, 56(%rsp)
-       movq %r11, 64(%rsp)
+       movq %rdx, 8(%rsp)
 
        call ftrace_return_to_handler
 
        movq %rax, 72(%rsp)
-       movq 64(%rsp), %r11
-       movq 56(%rsp), %r10
-       movq 48(%rsp), %r9
-       movq 40(%rsp), %r8
-       movq 32(%rsp), %rdi
-       movq 24(%rsp), %rsi
-       movq 16(%rsp), %rdx
-       movq 8(%rsp), %rcx
+       movq 8(%rsp), %rdx
        movq (%rsp), %rax
        addq $72, %rsp
        retq
@@ -1379,6 +1366,11 @@ END(xen_failsafe_callback)
 paranoidzeroentry_ist debug do_debug DEBUG_STACK
 paranoidzeroentry_ist int3 do_int3 DEBUG_STACK
 paranoiderrorentry stack_segment do_stack_segment
+#ifdef CONFIG_XEN
+zeroentry xen_debug do_debug
+zeroentry xen_int3 do_int3
+errorentry xen_stack_segment do_stack_segment
+#endif
 errorentry general_protection do_general_protection
 errorentry page_fault do_page_fault
 #ifdef CONFIG_X86_MCE
index 30683883e0cdcf0bd669cb439206fefaf74301f2..dc5ed4bdd88d36317ba5fc87554d10156a7f9132 100644 (file)
@@ -608,13 +608,6 @@ ignore_int:
 ENTRY(initial_code)
        .long i386_start_kernel
 
-.section .text
-/*
- * Real beginning of normal "text" segment
- */
-ENTRY(stext)
-ENTRY(_stext)
-
 /*
  * BSS section
  */
index c3fe010d74c8e8823793cd9ff816ee02adc8ebde..9a391bbb8ba83caffb48073831d3f1462cbae08e 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/io_apic.h>
 #include <asm/irq.h>
 #include <asm/idle.h>
+#include <asm/hw_irq.h>
 
 atomic_t irq_err_count;
 
@@ -24,9 +25,9 @@ void (*generic_interrupt_extension)(void) = NULL;
  */
 void ack_bad_irq(unsigned int irq)
 {
-       printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq);
+       if (printk_ratelimit())
+               pr_err("unexpected IRQ trap at vector %02x\n", irq);
 
-#ifdef CONFIG_X86_LOCAL_APIC
        /*
         * Currently unexpected vectors happen only on SMP and APIC.
         * We _must_ ack these because every local APIC has only N
@@ -36,9 +37,7 @@ void ack_bad_irq(unsigned int irq)
         * completely.
         * But only ack when the APIC is enabled -AK
         */
-       if (cpu_has_apic)
-               ack_APIC_irq();
-#endif
+       ack_APIC_irq();
 }
 
 #define irq_stats(x)           (&per_cpu(irq_stat, x))
@@ -178,7 +177,7 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
        sum += irq_stats(cpu)->irq_thermal_count;
 # ifdef CONFIG_X86_64
        sum += irq_stats(cpu)->irq_threshold_count;
-#endif
+# endif
 #endif
        return sum;
 }
@@ -213,14 +212,11 @@ unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
        irq = __get_cpu_var(vector_irq)[vector];
 
        if (!handle_irq(irq, regs)) {
-#ifdef CONFIG_X86_64
-               if (!disable_apic)
-                       ack_APIC_irq();
-#endif
+               ack_APIC_irq();
 
                if (printk_ratelimit())
-                       printk(KERN_EMERG "%s: %d.%d No irq handler for vector (irq %d)\n",
-                              __func__, smp_processor_id(), vector, irq);
+                       pr_emerg("%s: %d.%d No irq handler for vector (irq %d)\n",
+                               __func__, smp_processor_id(), vector, irq);
        }
 
        irq_exit();
similarity index 68%
rename from arch/x86/kernel/irqinit_32.c
rename to arch/x86/kernel/irqinit.c
index 368b0a8836f902be69531754a72fb75e7b9a4e24..2e08b10ad51abf5be458380780242b313f160e76 100644 (file)
@@ -1,20 +1,25 @@
+#include <linux/linkage.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
+#include <linux/timex.h>
 #include <linux/slab.h>
 #include <linux/random.h>
+#include <linux/kprobes.h>
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
 #include <linux/sysdev.h>
 #include <linux/bitops.h>
+#include <linux/acpi.h>
 #include <linux/io.h>
 #include <linux/delay.h>
 
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/timer.h>
+#include <asm/hw_irq.h>
 #include <asm/pgtable.h>
 #include <asm/desc.h>
 #include <asm/apic.h>
 #include <asm/i8259.h>
 #include <asm/traps.h>
 
+/*
+ * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
+ * (these are usually mapped to vectors 0x30-0x3f)
+ */
+
+/*
+ * The IO-APIC gives us many more interrupt sources. Most of these
+ * are unused but an SMP system is supposed to have enough memory ...
+ * sometimes (mostly wrt. hw bugs) we get corrupted vectors all
+ * across the spectrum, so we really want to be prepared to get all
+ * of these. Plus, more powerful systems might have more than 64
+ * IO-APIC registers.
+ *
+ * (these are usually mapped into the 0x30-0xff vector range)
+ */
 
+#ifdef CONFIG_X86_32
 /*
  * Note that on a 486, we don't want to do a SIGFPE on an irq13
  * as the irq is unreliable, and exception 16 works correctly
@@ -52,30 +73,7 @@ static struct irqaction fpu_irq = {
        .handler = math_error_irq,
        .name = "fpu",
 };
-
-void __init init_ISA_irqs(void)
-{
-       int i;
-
-#ifdef CONFIG_X86_LOCAL_APIC
-       init_bsp_APIC();
 #endif
-       init_8259A(0);
-
-       /*
-        * 16 old-style INTA-cycle interrupts:
-        */
-       for (i = 0; i < NR_IRQS_LEGACY; i++) {
-               struct irq_desc *desc = irq_to_desc(i);
-
-               desc->status = IRQ_DISABLED;
-               desc->action = NULL;
-               desc->depth = 1;
-
-               set_irq_chip_and_handler_name(i, &i8259A_chip,
-                                             handle_level_irq, "XT");
-       }
-}
 
 /*
  * IRQ2 is cascade interrupt to second interrupt controller
@@ -118,29 +116,37 @@ int vector_used_by_percpu_irq(unsigned int vector)
        return 0;
 }
 
-/* Overridden in paravirt.c */
-void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
-
-void __init native_init_IRQ(void)
+static void __init init_ISA_irqs(void)
 {
        int i;
 
-       /* Execute any quirks before the call gates are initialised: */
-       x86_quirk_pre_intr_init();
+#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
+       init_bsp_APIC();
+#endif
+       init_8259A(0);
 
        /*
-        * Cover the whole vector space, no vector can escape
-        * us. (some of these will be overridden and become
-        * 'special' SMP interrupts)
+        * 16 old-style INTA-cycle interrupts:
         */
-       for (i =  FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) {
-               /* SYSCALL_VECTOR was reserved in trap_init. */
-               if (i != SYSCALL_VECTOR)
-                       set_intr_gate(i, interrupt[i-FIRST_EXTERNAL_VECTOR]);
+       for (i = 0; i < NR_IRQS_LEGACY; i++) {
+               struct irq_desc *desc = irq_to_desc(i);
+
+               desc->status = IRQ_DISABLED;
+               desc->action = NULL;
+               desc->depth = 1;
+
+               set_irq_chip_and_handler_name(i, &i8259A_chip,
+                                             handle_level_irq, "XT");
        }
+}
 
+/* Overridden in paravirt.c */
+void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
 
-#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_SMP)
+static void __init smp_intr_init(void)
+{
+#ifdef CONFIG_SMP
+#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
        /*
         * The reschedule interrupt is a CPU-to-CPU reschedule-helper
         * IPI, driven by wakeup.
@@ -160,16 +166,27 @@ void __init native_init_IRQ(void)
        /* IPI for generic function call */
        alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
 
-       /* IPI for single call function */
+       /* IPI for generic single function call */
        alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR,
-                                call_function_single_interrupt);
+                       call_function_single_interrupt);
 
        /* Low priority IPI to cleanup after moving an irq */
        set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
        set_bit(IRQ_MOVE_CLEANUP_VECTOR, used_vectors);
 #endif
+#endif /* CONFIG_SMP */
+}
+
+static void __init apic_intr_init(void)
+{
+       smp_intr_init();
+
+#ifdef CONFIG_X86_64
+       alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
+       alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
+#endif
 
-#ifdef CONFIG_X86_LOCAL_APIC
+#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
        /* self generated IPI for local APIC timer */
        alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
 
@@ -179,16 +196,67 @@ void __init native_init_IRQ(void)
        /* IPI vectors for APIC spurious and error interrupts */
        alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
        alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
+
+       /* Performance monitoring interrupts: */
+# ifdef CONFIG_PERF_COUNTERS
+       alloc_intr_gate(LOCAL_PERF_VECTOR, perf_counter_interrupt);
+       alloc_intr_gate(LOCAL_PENDING_VECTOR, perf_pending_interrupt);
+# endif
+
 #endif
 
+#ifdef CONFIG_X86_32
 #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_MCE_P4THERMAL)
        /* thermal monitor LVT interrupt */
        alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
 #endif
+#endif
+}
+
+/**
+ * x86_quirk_pre_intr_init - initialisation prior to setting up interrupt vectors
+ *
+ * Description:
+ *     Perform any necessary interrupt initialisation prior to setting up
+ *     the "ordinary" interrupt call gates.  For legacy reasons, the ISA
+ *     interrupts should be initialised here if the machine emulates a PC
+ *     in any way.
+ **/
+static void __init x86_quirk_pre_intr_init(void)
+{
+#ifdef CONFIG_X86_32
+       if (x86_quirks->arch_pre_intr_init) {
+               if (x86_quirks->arch_pre_intr_init())
+                       return;
+       }
+#endif
+       init_ISA_irqs();
+}
+
+void __init native_init_IRQ(void)
+{
+       int i;
+
+       /* Execute any quirks before the call gates are initialised: */
+       x86_quirk_pre_intr_init();
+
+       apic_intr_init();
+
+       /*
+        * Cover the whole vector space, no vector can escape
+        * us. (some of these will be overridden and become
+        * 'special' SMP interrupts)
+        */
+       for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) {
+               /* IA32_SYSCALL_VECTOR could be used in trap_init already. */
+               if (!test_bit(i, used_vectors))
+                       set_intr_gate(i, interrupt[i-FIRST_EXTERNAL_VECTOR]);
+       }
 
        if (!acpi_ioapic)
                setup_irq(2, &irq2);
 
+#ifdef CONFIG_X86_32
        /*
         * Call quirks after call gates are initialised (usually add in
         * the architecture specific gates):
@@ -203,4 +271,5 @@ void __init native_init_IRQ(void)
                setup_irq(FPU_IRQ, &fpu_irq);
 
        irq_ctx_init(smp_processor_id());
+#endif
 }
diff --git a/arch/x86/kernel/irqinit_64.c b/arch/x86/kernel/irqinit_64.c
deleted file mode 100644 (file)
index 8cd1053..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-#include <linux/linkage.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/sysdev.h>
-#include <linux/bitops.h>
-#include <linux/acpi.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-
-#include <asm/atomic.h>
-#include <asm/system.h>
-#include <asm/hw_irq.h>
-#include <asm/pgtable.h>
-#include <asm/desc.h>
-#include <asm/apic.h>
-#include <asm/i8259.h>
-
-/*
- * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
- * (these are usually mapped to vectors 0x30-0x3f)
- */
-
-/*
- * The IO-APIC gives us many more interrupt sources. Most of these
- * are unused but an SMP system is supposed to have enough memory ...
- * sometimes (mostly wrt. hw bugs) we get corrupted vectors all
- * across the spectrum, so we really want to be prepared to get all
- * of these. Plus, more powerful systems might have more than 64
- * IO-APIC registers.
- *
- * (these are usually mapped into the 0x30-0xff vector range)
- */
-
-/*
- * IRQ2 is cascade interrupt to second interrupt controller
- */
-
-static struct irqaction irq2 = {
-       .handler = no_action,
-       .name = "cascade",
-};
-DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
-       [0 ... IRQ0_VECTOR - 1] = -1,
-       [IRQ0_VECTOR] = 0,
-       [IRQ1_VECTOR] = 1,
-       [IRQ2_VECTOR] = 2,
-       [IRQ3_VECTOR] = 3,
-       [IRQ4_VECTOR] = 4,
-       [IRQ5_VECTOR] = 5,
-       [IRQ6_VECTOR] = 6,
-       [IRQ7_VECTOR] = 7,
-       [IRQ8_VECTOR] = 8,
-       [IRQ9_VECTOR] = 9,
-       [IRQ10_VECTOR] = 10,
-       [IRQ11_VECTOR] = 11,
-       [IRQ12_VECTOR] = 12,
-       [IRQ13_VECTOR] = 13,
-       [IRQ14_VECTOR] = 14,
-       [IRQ15_VECTOR] = 15,
-       [IRQ15_VECTOR + 1 ... NR_VECTORS - 1] = -1
-};
-
-int vector_used_by_percpu_irq(unsigned int vector)
-{
-       int cpu;
-
-       for_each_online_cpu(cpu) {
-               if (per_cpu(vector_irq, cpu)[vector] != -1)
-                       return 1;
-       }
-
-       return 0;
-}
-
-static void __init init_ISA_irqs(void)
-{
-       int i;
-
-       init_bsp_APIC();
-       init_8259A(0);
-
-       for (i = 0; i < NR_IRQS_LEGACY; i++) {
-               struct irq_desc *desc = irq_to_desc(i);
-
-               desc->status = IRQ_DISABLED;
-               desc->action = NULL;
-               desc->depth = 1;
-
-               /*
-                * 16 old-style INTA-cycle interrupts:
-                */
-               set_irq_chip_and_handler_name(i, &i8259A_chip,
-                                                     handle_level_irq, "XT");
-       }
-}
-
-void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
-
-static void __init smp_intr_init(void)
-{
-#ifdef CONFIG_SMP
-       /*
-        * The reschedule interrupt is a CPU-to-CPU reschedule-helper
-        * IPI, driven by wakeup.
-        */
-       alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
-
-       /* IPIs for invalidation */
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+0, invalidate_interrupt0);
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+1, invalidate_interrupt1);
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+2, invalidate_interrupt2);
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+3, invalidate_interrupt3);
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+4, invalidate_interrupt4);
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+5, invalidate_interrupt5);
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+6, invalidate_interrupt6);
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+7, invalidate_interrupt7);
-
-       /* IPI for generic function call */
-       alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
-
-       /* IPI for generic single function call */
-       alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR,
-                       call_function_single_interrupt);
-
-       /* Low priority IPI to cleanup after moving an irq */
-       set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
-       set_bit(IRQ_MOVE_CLEANUP_VECTOR, used_vectors);
-#endif
-}
-
-static void __init apic_intr_init(void)
-{
-       smp_intr_init();
-
-       alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
-       alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
-
-       /* self generated IPI for local APIC timer */
-       alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
-
-       /* generic IPI for platform specific use */
-       alloc_intr_gate(GENERIC_INTERRUPT_VECTOR, generic_interrupt);
-
-       /* IPI vectors for APIC spurious and error interrupts */
-       alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
-       alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
-}
-
-void __init native_init_IRQ(void)
-{
-       int i;
-
-       init_ISA_irqs();
-       /*
-        * Cover the whole vector space, no vector can escape
-        * us. (some of these will be overridden and become
-        * 'special' SMP interrupts)
-        */
-       for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
-               int vector = FIRST_EXTERNAL_VECTOR + i;
-               if (vector != IA32_SYSCALL_VECTOR)
-                       set_intr_gate(vector, interrupt[i]);
-       }
-
-       apic_intr_init();
-
-       if (!acpi_ioapic)
-               setup_irq(2, &irq2);
-}
index b1f4dffb919e8c708421cb8c29af80ad50d6a7c9..8d82a77a3f3b96ea3c0dc37e91551dddc7e10b51 100644 (file)
@@ -142,7 +142,7 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
        gdb_regs32[GDB_PS]      = *(unsigned long *)(p->thread.sp + 8);
        gdb_regs32[GDB_CS]      = __KERNEL_CS;
        gdb_regs32[GDB_SS]      = __KERNEL_DS;
-       gdb_regs[GDB_PC]        = p->thread.ip;
+       gdb_regs[GDB_PC]        = 0;
        gdb_regs[GDB_R8]        = 0;
        gdb_regs[GDB_R9]        = 0;
        gdb_regs[GDB_R10]       = 0;
index 33019ddb56b452ce736f4b70fcb5d4efe8d0ae9d..a78ecad0c900ff646b8c826c08cd54b094815b5a 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/mm.h>
 #include <linux/highmem.h>
 #include <linux/hardirq.h>
+#include <asm/timer.h>
 
 #define MMU_QUEUE_SIZE 1024
 
@@ -195,7 +196,7 @@ static void kvm_leave_lazy_mmu(void)
        struct kvm_para_state *state = kvm_para_state();
 
        mmu_queue_flush(state);
-       paravirt_leave_lazy(paravirt_get_lazy_mode());
+       paravirt_leave_lazy_mmu();
        state->mode = paravirt_get_lazy_mode();
 }
 
@@ -230,6 +231,9 @@ static void paravirt_ops_setup(void)
                pv_mmu_ops.lazy_mode.enter = kvm_enter_lazy_mmu;
                pv_mmu_ops.lazy_mode.leave = kvm_leave_lazy_mmu;
        }
+#ifdef CONFIG_X86_IO_APIC
+       no_timer_check = 1;
+#endif
 }
 
 void __init kvm_guest_init(void)
index 453b5795a5c6a23817f8e833f722d6140c6be644..366baa179913dfc3e3e865480e82008a9ab5071a 100644 (file)
  *  Licensed under the terms of the GNU General Public
  *  License version 2. See file COPYING for details.
  */
-#include <linux/platform_device.h>
-#include <linux/capability.h>
-#include <linux/miscdevice.h>
 #include <linux/firmware.h>
-#include <linux/spinlock.h>
-#include <linux/cpumask.h>
 #include <linux/pci_ids.h>
 #include <linux/uaccess.h>
 #include <linux/vmalloc.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/cpu.h>
 #include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
 
 #include <asm/microcode.h>
 #include <asm/processor.h>
@@ -79,9 +67,6 @@ struct microcode_amd {
 #define UCODE_CONTAINER_SECTION_HDR    8
 #define UCODE_CONTAINER_HEADER_SIZE    12
 
-/* serialize access to the physical write */
-static DEFINE_SPINLOCK(microcode_update_lock);
-
 static struct equiv_cpu_entry *equiv_cpu_table;
 
 static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
@@ -144,9 +129,8 @@ static int get_matching_microcode(int cpu, void *mc, int rev)
        return 1;
 }
 
-static void apply_microcode_amd(int cpu)
+static int apply_microcode_amd(int cpu)
 {
-       unsigned long flags;
        u32 rev, dummy;
        int cpu_num = raw_smp_processor_id();
        struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
@@ -156,25 +140,25 @@ static void apply_microcode_amd(int cpu)
        BUG_ON(cpu_num != cpu);
 
        if (mc_amd == NULL)
-               return;
+               return 0;
 
-       spin_lock_irqsave(&microcode_update_lock, flags);
        wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code);
        /* get patch id after patching */
        rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
-       spin_unlock_irqrestore(&microcode_update_lock, flags);
 
        /* check current patch id and patch's id for match */
        if (rev != mc_amd->hdr.patch_id) {
                printk(KERN_ERR "microcode: CPU%d: update failed "
                       "(for patch_level=0x%x)\n", cpu, mc_amd->hdr.patch_id);
-               return;
+               return -1;
        }
 
        printk(KERN_INFO "microcode: CPU%d: updated (new patch_level=0x%x)\n",
               cpu, rev);
 
        uci->cpu_sig.rev = rev;
+
+       return 0;
 }
 
 static int get_ucode_data(void *to, const u8 *from, size_t n)
@@ -257,13 +241,12 @@ static int install_equiv_cpu_table(const u8 *buf)
 
 static void free_equiv_cpu_table(void)
 {
-       if (equiv_cpu_table) {
-               vfree(equiv_cpu_table);
-               equiv_cpu_table = NULL;
-       }
+       vfree(equiv_cpu_table);
+       equiv_cpu_table = NULL;
 }
 
-static int generic_load_microcode(int cpu, const u8 *data, size_t size)
+static enum ucode_state
+generic_load_microcode(int cpu, const u8 *data, size_t size)
 {
        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
        const u8 *ucode_ptr = data;
@@ -272,12 +255,13 @@ static int generic_load_microcode(int cpu, const u8 *data, size_t size)
        int new_rev = uci->cpu_sig.rev;
        unsigned int leftover;
        unsigned long offset;
+       enum ucode_state state = UCODE_OK;
 
        offset = install_equiv_cpu_table(ucode_ptr);
        if (!offset) {
                printk(KERN_ERR "microcode: failed to create "
                       "equivalent cpu table\n");
-               return -EINVAL;
+               return UCODE_ERROR;
        }
 
        ucode_ptr += offset;
@@ -293,8 +277,7 @@ static int generic_load_microcode(int cpu, const u8 *data, size_t size)
 
                mc_header = (struct microcode_header_amd *)mc;
                if (get_matching_microcode(cpu, mc, new_rev)) {
-                       if (new_mc)
-                               vfree(new_mc);
+                       vfree(new_mc);
                        new_rev = mc_header->patch_id;
                        new_mc  = mc;
                } else
@@ -306,34 +289,32 @@ static int generic_load_microcode(int cpu, const u8 *data, size_t size)
 
        if (new_mc) {
                if (!leftover) {
-                       if (uci->mc)
-                               vfree(uci->mc);
+                       vfree(uci->mc);
                        uci->mc = new_mc;
                        pr_debug("microcode: CPU%d found a matching microcode "
                                 "update with version 0x%x (current=0x%x)\n",
                                 cpu, new_rev, uci->cpu_sig.rev);
-               } else
+               } else {
                        vfree(new_mc);
-       }
+                       state = UCODE_ERROR;
+               }
+       } else
+               state = UCODE_NFOUND;
 
        free_equiv_cpu_table();
 
-       return (int)leftover;
+       return state;
 }
 
-static int request_microcode_fw(int cpu, struct device *device)
+static enum ucode_state request_microcode_fw(int cpu, struct device *device)
 {
        const char *fw_name = "amd-ucode/microcode_amd.bin";
        const struct firmware *firmware;
-       int ret;
-
-       /* We should bind the task to the CPU */
-       BUG_ON(cpu != raw_smp_processor_id());
+       enum ucode_state ret;
 
-       ret = request_firmware(&firmware, fw_name, device);
-       if (ret) {
+       if (request_firmware(&firmware, fw_name, device)) {
                printk(KERN_ERR "microcode: failed to load file %s\n", fw_name);
-               return ret;
+               return UCODE_NFOUND;
        }
 
        ret = generic_load_microcode(cpu, firmware->data, firmware->size);
@@ -343,11 +324,12 @@ static int request_microcode_fw(int cpu, struct device *device)
        return ret;
 }
 
-static int request_microcode_user(int cpu, const void __user *buf, size_t size)
+static enum ucode_state
+request_microcode_user(int cpu, const void __user *buf, size_t size)
 {
        printk(KERN_INFO "microcode: AMD microcode update via "
               "/dev/cpu/microcode not supported\n");
-       return -1;
+       return UCODE_ERROR;
 }
 
 static void microcode_fini_cpu_amd(int cpu)
index 98c470c069d150f26af3125a7690a25689614362..9c4461501fcbb9618ac3ce12fef93f990b8f3955 100644 (file)
  *             Thanks to Stuart Swales for pointing out this bug.
  */
 #include <linux/platform_device.h>
-#include <linux/capability.h>
 #include <linux/miscdevice.h>
-#include <linux/firmware.h>
+#include <linux/capability.h>
 #include <linux/smp_lock.h>
-#include <linux/spinlock.h>
-#include <linux/cpumask.h>
-#include <linux/uaccess.h>
-#include <linux/vmalloc.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/slab.h>
 #include <linux/cpu.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 
 #include <asm/microcode.h>
 #include <asm/processor.h>
-#include <asm/msr.h>
 
 MODULE_DESCRIPTION("Microcode Update Driver");
 MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
@@ -101,36 +92,110 @@ MODULE_LICENSE("GPL");
 
 static struct microcode_ops    *microcode_ops;
 
-/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
+/*
+ * Synchronization.
+ *
+ * All non cpu-hotplug-callback call sites use:
+ *
+ * - microcode_mutex to synchronize with each other;
+ * - get/put_online_cpus() to synchronize with
+ *   the cpu-hotplug-callback call sites.
+ *
+ * We guarantee that only a single cpu is being
+ * updated at any particular moment of time.
+ */
 static DEFINE_MUTEX(microcode_mutex);
 
 struct ucode_cpu_info          ucode_cpu_info[NR_CPUS];
 EXPORT_SYMBOL_GPL(ucode_cpu_info);
 
+/*
+ * Operations that are run on a target cpu:
+ */
+
+struct cpu_info_ctx {
+       struct cpu_signature    *cpu_sig;
+       int                     err;
+};
+
+static void collect_cpu_info_local(void *arg)
+{
+       struct cpu_info_ctx *ctx = arg;
+
+       ctx->err = microcode_ops->collect_cpu_info(smp_processor_id(),
+                                                  ctx->cpu_sig);
+}
+
+static int collect_cpu_info_on_target(int cpu, struct cpu_signature *cpu_sig)
+{
+       struct cpu_info_ctx ctx = { .cpu_sig = cpu_sig, .err = 0 };
+       int ret;
+
+       ret = smp_call_function_single(cpu, collect_cpu_info_local, &ctx, 1);
+       if (!ret)
+               ret = ctx.err;
+
+       return ret;
+}
+
+static int collect_cpu_info(int cpu)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       int ret;
+
+       memset(uci, 0, sizeof(*uci));
+
+       ret = collect_cpu_info_on_target(cpu, &uci->cpu_sig);
+       if (!ret)
+               uci->valid = 1;
+
+       return ret;
+}
+
+struct apply_microcode_ctx {
+       int err;
+};
+
+static void apply_microcode_local(void *arg)
+{
+       struct apply_microcode_ctx *ctx = arg;
+
+       ctx->err = microcode_ops->apply_microcode(smp_processor_id());
+}
+
+static int apply_microcode_on_target(int cpu)
+{
+       struct apply_microcode_ctx ctx = { .err = 0 };
+       int ret;
+
+       ret = smp_call_function_single(cpu, apply_microcode_local, &ctx, 1);
+       if (!ret)
+               ret = ctx.err;
+
+       return ret;
+}
+
 #ifdef CONFIG_MICROCODE_OLD_INTERFACE
 static int do_microcode_update(const void __user *buf, size_t size)
 {
-       cpumask_t old;
        int error = 0;
        int cpu;
 
-       old = current->cpus_allowed;
-
        for_each_online_cpu(cpu) {
                struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+               enum ucode_state ustate;
 
                if (!uci->valid)
                        continue;
 
-               set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-               error = microcode_ops->request_microcode_user(cpu, buf, size);
-               if (error < 0)
-                       goto out;
-               if (!error)
-                       microcode_ops->apply_microcode(cpu);
+               ustate = microcode_ops->request_microcode_user(cpu, buf, size);
+               if (ustate == UCODE_ERROR) {
+                       error = -1;
+                       break;
+               } else if (ustate == UCODE_OK)
+                       apply_microcode_on_target(cpu);
        }
-out:
-       set_cpus_allowed_ptr(current, &old);
+
        return error;
 }
 
@@ -143,19 +208,17 @@ static int microcode_open(struct inode *unused1, struct file *unused2)
 static ssize_t microcode_write(struct file *file, const char __user *buf,
                               size_t len, loff_t *ppos)
 {
-       ssize_t ret;
+       ssize_t ret = -EINVAL;
 
        if ((len >> PAGE_SHIFT) > num_physpages) {
-               printk(KERN_ERR "microcode: too much data (max %ld pages)\n",
-                      num_physpages);
-               return -EINVAL;
+               pr_err("microcode: too much data (max %ld pages)\n", num_physpages);
+               return ret;
        }
 
        get_online_cpus();
        mutex_lock(&microcode_mutex);
 
-       ret = do_microcode_update(buf, len);
-       if (!ret)
+       if (do_microcode_update(buf, len) == 0)
                ret = (ssize_t)len;
 
        mutex_unlock(&microcode_mutex);
@@ -165,15 +228,15 @@ static ssize_t microcode_write(struct file *file, const char __user *buf,
 }
 
 static const struct file_operations microcode_fops = {
-       .owner          = THIS_MODULE,
-       .write          = microcode_write,
-       .open           = microcode_open,
+       .owner                  = THIS_MODULE,
+       .write                  = microcode_write,
+       .open                   = microcode_open,
 };
 
 static struct miscdevice microcode_dev = {
-       .minor          = MICROCODE_MINOR,
-       .name           = "microcode",
-       .fops           = &microcode_fops,
+       .minor                  = MICROCODE_MINOR,
+       .name                   = "microcode",
+       .fops                   = &microcode_fops,
 };
 
 static int __init microcode_dev_init(void)
@@ -182,9 +245,7 @@ static int __init microcode_dev_init(void)
 
        error = misc_register(&microcode_dev);
        if (error) {
-               printk(KERN_ERR
-                       "microcode: can't misc_register on minor=%d\n",
-                       MICROCODE_MINOR);
+               pr_err("microcode: can't misc_register on minor=%d\n", MICROCODE_MINOR);
                return error;
        }
 
@@ -205,42 +266,51 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
 /* fake device for request_firmware */
 static struct platform_device  *microcode_pdev;
 
-static long reload_for_cpu(void *unused)
+static int reload_for_cpu(int cpu)
 {
-       struct ucode_cpu_info *uci = ucode_cpu_info + smp_processor_id();
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
        int err = 0;
 
        mutex_lock(&microcode_mutex);
        if (uci->valid) {
-               err = microcode_ops->request_microcode_fw(smp_processor_id(),
-                                                         &microcode_pdev->dev);
-               if (!err)
-                       microcode_ops->apply_microcode(smp_processor_id());
+               enum ucode_state ustate;
+
+               ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev);
+               if (ustate == UCODE_OK)
+                       apply_microcode_on_target(cpu);
+               else
+                       if (ustate == UCODE_ERROR)
+                               err = -EINVAL;
        }
        mutex_unlock(&microcode_mutex);
+
        return err;
 }
 
 static ssize_t reload_store(struct sys_device *dev,
                            struct sysdev_attribute *attr,
-                           const char *buf, size_t sz)
+                           const char *buf, size_t size)
 {
-       char *end;
-       unsigned long val = simple_strtoul(buf, &end, 0);
-       int err = 0;
+       unsigned long val;
        int cpu = dev->id;
+       int ret = 0;
+       char *end;
 
+       val = simple_strtoul(buf, &end, 0);
        if (end == buf)
                return -EINVAL;
+
        if (val == 1) {
                get_online_cpus();
                if (cpu_online(cpu))
-                       err = work_on_cpu(cpu, reload_for_cpu, NULL);
+                       ret = reload_for_cpu(cpu);
                put_online_cpus();
        }
-       if (err)
-               return err;
-       return sz;
+
+       if (!ret)
+               ret = size;
+
+       return ret;
 }
 
 static ssize_t version_show(struct sys_device *dev,
@@ -271,11 +341,11 @@ static struct attribute *mc_default_attrs[] = {
 };
 
 static struct attribute_group mc_attr_group = {
-       .attrs          = mc_default_attrs,
-       .name           = "microcode",
+       .attrs                  = mc_default_attrs,
+       .name                   = "microcode",
 };
 
-static void __microcode_fini_cpu(int cpu)
+static void microcode_fini_cpu(int cpu)
 {
        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
 
@@ -283,103 +353,68 @@ static void __microcode_fini_cpu(int cpu)
        uci->valid = 0;
 }
 
-static void microcode_fini_cpu(int cpu)
-{
-       mutex_lock(&microcode_mutex);
-       __microcode_fini_cpu(cpu);
-       mutex_unlock(&microcode_mutex);
-}
-
-static void collect_cpu_info(int cpu)
+static enum ucode_state microcode_resume_cpu(int cpu)
 {
        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
 
-       memset(uci, 0, sizeof(*uci));
-       if (!microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig))
-               uci->valid = 1;
+       if (!uci->mc)
+               return UCODE_NFOUND;
+
+       pr_debug("microcode: CPU%d updated upon resume\n", cpu);
+       apply_microcode_on_target(cpu);
+
+       return UCODE_OK;
 }
 
-static int microcode_resume_cpu(int cpu)
+static enum ucode_state microcode_init_cpu(int cpu)
 {
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-       struct cpu_signature nsig;
+       enum ucode_state ustate;
 
-       pr_debug("microcode: CPU%d resumed\n", cpu);
+       if (collect_cpu_info(cpu))
+               return UCODE_ERROR;
 
-       if (!uci->mc)
-               return 1;
+       /* --dimm. Trigger a delayed update? */
+       if (system_state != SYSTEM_RUNNING)
+               return UCODE_NFOUND;
 
-       /*
-        * Let's verify that the 'cached' ucode does belong
-        * to this cpu (a bit of paranoia):
-        */
-       if (microcode_ops->collect_cpu_info(cpu, &nsig)) {
-               __microcode_fini_cpu(cpu);
-               printk(KERN_ERR "failed to collect_cpu_info for resuming cpu #%d\n",
-                               cpu);
-               return -1;
-       }
+       ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev);
 
-       if ((nsig.sig != uci->cpu_sig.sig) || (nsig.pf != uci->cpu_sig.pf)) {
-               __microcode_fini_cpu(cpu);
-               printk(KERN_ERR "cached ucode doesn't match the resuming cpu #%d\n",
-                               cpu);
-               /* Should we look for a new ucode here? */
-               return 1;
+       if (ustate == UCODE_OK) {
+               pr_debug("microcode: CPU%d updated upon init\n", cpu);
+               apply_microcode_on_target(cpu);
        }
 
-       return 0;
+       return ustate;
 }
 
-static long microcode_update_cpu(void *unused)
+static enum ucode_state microcode_update_cpu(int cpu)
 {
-       struct ucode_cpu_info *uci = ucode_cpu_info + smp_processor_id();
-       int err = 0;
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       enum ucode_state ustate;
 
-       /*
-        * Check if the system resume is in progress (uci->valid != NULL),
-        * otherwise just request a firmware:
-        */
-       if (uci->valid) {
-               err = microcode_resume_cpu(smp_processor_id());
-       } else {
-               collect_cpu_info(smp_processor_id());
-               if (uci->valid && system_state == SYSTEM_RUNNING)
-                       err = microcode_ops->request_microcode_fw(
-                                       smp_processor_id(),
-                                       &microcode_pdev->dev);
-       }
-       if (!err)
-               microcode_ops->apply_microcode(smp_processor_id());
-       return err;
-}
+       if (uci->valid)
+               ustate = microcode_resume_cpu(cpu);
+       else
+               ustate = microcode_init_cpu(cpu);
 
-static int microcode_init_cpu(int cpu)
-{
-       int err;
-       mutex_lock(&microcode_mutex);
-       err = work_on_cpu(cpu, microcode_update_cpu, NULL);
-       mutex_unlock(&microcode_mutex);
-
-       return err;
+       return ustate;
 }
 
 static int mc_sysdev_add(struct sys_device *sys_dev)
 {
        int err, cpu = sys_dev->id;
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
 
        if (!cpu_online(cpu))
                return 0;
 
        pr_debug("microcode: CPU%d added\n", cpu);
-       memset(uci, 0, sizeof(*uci));
 
        err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
        if (err)
                return err;
 
-       err = microcode_init_cpu(cpu);
+       if (microcode_init_cpu(cpu) == UCODE_ERROR)
+               err = -EINVAL;
 
        return err;
 }
@@ -400,19 +435,30 @@ static int mc_sysdev_remove(struct sys_device *sys_dev)
 static int mc_sysdev_resume(struct sys_device *dev)
 {
        int cpu = dev->id;
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
 
        if (!cpu_online(cpu))
                return 0;
 
-       /* only CPU 0 will apply ucode here */
-       microcode_update_cpu(NULL);
+       /*
+        * All non-bootup cpus are still disabled,
+        * so only CPU 0 will apply ucode here.
+        *
+        * Moreover, there can be no concurrent
+        * updates from any other places at this point.
+        */
+       WARN_ON(cpu != 0);
+
+       if (uci->valid && uci->mc)
+               microcode_ops->apply_microcode(cpu);
+
        return 0;
 }
 
 static struct sysdev_driver mc_sysdev_driver = {
-       .add            = mc_sysdev_add,
-       .remove         = mc_sysdev_remove,
-       .resume         = mc_sysdev_resume,
+       .add                    = mc_sysdev_add,
+       .remove                 = mc_sysdev_remove,
+       .resume                 = mc_sysdev_resume,
 };
 
 static __cpuinit int
@@ -425,15 +471,12 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
        switch (action) {
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
-               if (microcode_init_cpu(cpu))
-                       printk(KERN_ERR "microcode: failed to init CPU%d\n",
-                              cpu);
+               microcode_update_cpu(cpu);
        case CPU_DOWN_FAILED:
        case CPU_DOWN_FAILED_FROZEN:
                pr_debug("microcode: CPU%d added\n", cpu);
                if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
-                       printk(KERN_ERR "microcode: Failed to create the sysfs "
-                               "group for CPU%d\n", cpu);
+                       pr_err("microcode: Failed to create group for CPU%d\n", cpu);
                break;
        case CPU_DOWN_PREPARE:
        case CPU_DOWN_PREPARE_FROZEN:
@@ -465,13 +508,10 @@ static int __init microcode_init(void)
                microcode_ops = init_amd_microcode();
 
        if (!microcode_ops) {
-               printk(KERN_ERR "microcode: no support for this CPU vendor\n");
+               pr_err("microcode: no support for this CPU vendor\n");
                return -ENODEV;
        }
 
-       error = microcode_dev_init();
-       if (error)
-               return error;
        microcode_pdev = platform_device_register_simple("microcode", -1,
                                                         NULL, 0);
        if (IS_ERR(microcode_pdev)) {
@@ -480,23 +520,31 @@ static int __init microcode_init(void)
        }
 
        get_online_cpus();
+       mutex_lock(&microcode_mutex);
+
        error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
+
+       mutex_unlock(&microcode_mutex);
        put_online_cpus();
+
        if (error) {
-               microcode_dev_exit();
                platform_device_unregister(microcode_pdev);
                return error;
        }
 
+       error = microcode_dev_init();
+       if (error)
+               return error;
+
        register_hotcpu_notifier(&mc_cpu_notifier);
 
-       printk(KERN_INFO
-              "Microcode Update Driver: v" MICROCODE_VERSION
+       pr_info("Microcode Update Driver: v" MICROCODE_VERSION
               " <tigran@aivazian.fsnet.co.uk>,"
               " Peter Oruba\n");
 
        return 0;
 }
+module_init(microcode_init);
 
 static void __exit microcode_exit(void)
 {
@@ -505,16 +553,17 @@ static void __exit microcode_exit(void)
        unregister_hotcpu_notifier(&mc_cpu_notifier);
 
        get_online_cpus();
+       mutex_lock(&microcode_mutex);
+
        sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
+
+       mutex_unlock(&microcode_mutex);
        put_online_cpus();
 
        platform_device_unregister(microcode_pdev);
 
        microcode_ops = NULL;
 
-       printk(KERN_INFO
-              "Microcode Update Driver: v" MICROCODE_VERSION " removed.\n");
+       pr_info("Microcode Update Driver: v" MICROCODE_VERSION " removed.\n");
 }
-
-module_init(microcode_init);
 module_exit(microcode_exit);
index 149b9ec7c1ab72fcd20c2f2ab84cc511b3d707e7..0d334ddd0a9642a2c05485e9e31394f8b1e98a3b 100644 (file)
  *             Fix sigmatch() macro to handle old CPUs with pf == 0.
  *             Thanks to Stuart Swales for pointing out this bug.
  */
-#include <linux/platform_device.h>
-#include <linux/capability.h>
-#include <linux/miscdevice.h>
 #include <linux/firmware.h>
-#include <linux/smp_lock.h>
-#include <linux/spinlock.h>
-#include <linux/cpumask.h>
 #include <linux/uaccess.h>
-#include <linux/vmalloc.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/cpu.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
+#include <linux/vmalloc.h>
 
 #include <asm/microcode.h>
 #include <asm/processor.h>
@@ -150,13 +137,9 @@ struct extended_sigtable {
 
 #define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
 
-/* serialize access to the physical write to MSR 0x79 */
-static DEFINE_SPINLOCK(microcode_update_lock);
-
 static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
 {
        struct cpuinfo_x86 *c = &cpu_data(cpu_num);
-       unsigned long flags;
        unsigned int val[2];
 
        memset(csig, 0, sizeof(*csig));
@@ -176,18 +159,14 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
                csig->pf = 1 << ((val[1] >> 18) & 7);
        }
 
-       /* serialize access to the physical write to MSR 0x79 */
-       spin_lock_irqsave(&microcode_update_lock, flags);
-
        wrmsr(MSR_IA32_UCODE_REV, 0, 0);
        /* see notes above for revision 1.07.  Apparent chip bug */
        sync_core();
        /* get the current revision from MSR 0x8B */
        rdmsr(MSR_IA32_UCODE_REV, val[0], csig->rev);
-       spin_unlock_irqrestore(&microcode_update_lock, flags);
 
-       pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
-                       csig->sig, csig->pf, csig->rev);
+       printk(KERN_INFO "microcode: CPU%d sig=0x%x, pf=0x%x, revision=0x%x\n",
+                       cpu_num, csig->sig, csig->pf, csig->rev);
 
        return 0;
 }
@@ -318,11 +297,10 @@ get_matching_microcode(struct cpu_signature *cpu_sig, void *mc, int rev)
        return 0;
 }
 
-static void apply_microcode(int cpu)
+static int apply_microcode(int cpu)
 {
        struct microcode_intel *mc_intel;
        struct ucode_cpu_info *uci;
-       unsigned long flags;
        unsigned int val[2];
        int cpu_num;
 
@@ -334,10 +312,7 @@ static void apply_microcode(int cpu)
        BUG_ON(cpu_num != cpu);
 
        if (mc_intel == NULL)
-               return;
-
-       /* serialize access to the physical write to MSR 0x79 */
-       spin_lock_irqsave(&microcode_update_lock, flags);
+               return 0;
 
        /* write microcode via MSR 0x79 */
        wrmsr(MSR_IA32_UCODE_WRITE,
@@ -351,30 +326,32 @@ static void apply_microcode(int cpu)
        /* get the current revision from MSR 0x8B */
        rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
 
-       spin_unlock_irqrestore(&microcode_update_lock, flags);
        if (val[1] != mc_intel->hdr.rev) {
-               printk(KERN_ERR "microcode: CPU%d update from revision "
-                               "0x%x to 0x%x failed\n",
-                       cpu_num, uci->cpu_sig.rev, val[1]);
-               return;
+               printk(KERN_ERR "microcode: CPU%d update "
+                               "to revision 0x%x failed\n",
+                       cpu_num, mc_intel->hdr.rev);
+               return -1;
        }
-       printk(KERN_INFO "microcode: CPU%d updated from revision "
-                        "0x%x to 0x%x, date = %04x-%02x-%02x \n",
-               cpu_num, uci->cpu_sig.rev, val[1],
+       printk(KERN_INFO "microcode: CPU%d updated to revision "
+                        "0x%x, date = %04x-%02x-%02x \n",
+               cpu_num, val[1],
                mc_intel->hdr.date & 0xffff,
                mc_intel->hdr.date >> 24,
                (mc_intel->hdr.date >> 16) & 0xff);
 
        uci->cpu_sig.rev = val[1];
+
+       return 0;
 }
 
-static int generic_load_microcode(int cpu, void *data, size_t size,
-               int (*get_ucode_data)(void *, const void *, size_t))
+static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
+                               int (*get_ucode_data)(void *, const void *, size_t))
 {
        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
        u8 *ucode_ptr = data, *new_mc = NULL, *mc;
        int new_rev = uci->cpu_sig.rev;
        unsigned int leftover = size;
+       enum ucode_state state = UCODE_OK;
 
        while (leftover) {
                struct microcode_header_intel mc_header;
@@ -412,11 +389,15 @@ static int generic_load_microcode(int cpu, void *data, size_t size,
                leftover  -= mc_size;
        }
 
-       if (!new_mc)
+       if (leftover) {
+               if (new_mc)
+                       vfree(new_mc);
+               state = UCODE_ERROR;
                goto out;
+       }
 
-       if (leftover) {
-               vfree(new_mc);
+       if (!new_mc) {
+               state = UCODE_NFOUND;
                goto out;
        }
 
@@ -427,9 +408,8 @@ static int generic_load_microcode(int cpu, void *data, size_t size,
        pr_debug("microcode: CPU%d found a matching microcode update with"
                 " version 0x%x (current=0x%x)\n",
                        cpu, new_rev, uci->cpu_sig.rev);
-
- out:
-       return (int)leftover;
+out:
+       return state;
 }
 
 static int get_ucode_fw(void *to, const void *from, size_t n)
@@ -438,21 +418,19 @@ static int get_ucode_fw(void *to, const void *from, size_t n)
        return 0;
 }
 
-static int request_microcode_fw(int cpu, struct device *device)
+static enum ucode_state request_microcode_fw(int cpu, struct device *device)
 {
        char name[30];
        struct cpuinfo_x86 *c = &cpu_data(cpu);
        const struct firmware *firmware;
-       int ret;
+       enum ucode_state ret;
 
-       /* We should bind the task to the CPU */
-       BUG_ON(cpu != raw_smp_processor_id());
        sprintf(name, "intel-ucode/%02x-%02x-%02x",
                c->x86, c->x86_model, c->x86_mask);
-       ret = request_firmware(&firmware, name, device);
-       if (ret) {
+
+       if (request_firmware(&firmware, name, device)) {
                pr_debug("microcode: data file %s load failed\n", name);
-               return ret;
+               return UCODE_NFOUND;
        }
 
        ret = generic_load_microcode(cpu, (void *)firmware->data,
@@ -468,11 +446,9 @@ static int get_ucode_user(void *to, const void *from, size_t n)
        return copy_from_user(to, from, n);
 }
 
-static int request_microcode_user(int cpu, const void __user *buf, size_t size)
+static enum ucode_state
+request_microcode_user(int cpu, const void __user *buf, size_t size)
 {
-       /* We should bind the task to the CPU */
-       BUG_ON(cpu != raw_smp_processor_id());
-
        return generic_load_microcode(cpu, (void *)buf, size, &get_ucode_user);
 }
 
index 70fd7e414c1544aadf5de5573e67294e88cac16c..651c93b28862a5ea04f3fdfc883533ff843b2583 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/acpi.h>
 #include <linux/module.h>
 #include <linux/smp.h>
+#include <linux/pci.h>
 
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
@@ -870,24 +871,17 @@ static
 inline void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare) {}
 #endif /* CONFIG_X86_IO_APIC */
 
-static int check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length,
-                     int count)
+static int
+check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length, int count)
 {
-       if (!mpc_new_phys) {
-               pr_info("No spare slots, try to append...take your risk, "
-                       "new mpc_length %x\n", count);
-       } else {
-               if (count <= mpc_new_length)
-                       pr_info("No spare slots, try to append..., "
-                               "new mpc_length %x\n", count);
-               else {
-                       pr_err("mpc_new_length %lx is too small\n",
-                               mpc_new_length);
-                       return -1;
-               }
+       int ret = 0;
+
+       if (!mpc_new_phys || count <= mpc_new_length) {
+               WARN(1, "update_mptable: No spare slots (length: %x)\n", count);
+               return -1;
        }
 
-       return 0;
+       return ret;
 }
 
 static int  __init replace_intsrc_all(struct mpc_table *mpc,
@@ -946,7 +940,7 @@ static int  __init replace_intsrc_all(struct mpc_table *mpc,
                } else {
                        struct mpc_intsrc *m = (struct mpc_intsrc *)mpt;
                        count += sizeof(struct mpc_intsrc);
-                       if (!check_slot(mpc_new_phys, mpc_new_length, count))
+                       if (check_slot(mpc_new_phys, mpc_new_length, count) < 0)
                                goto out;
                        assign_to_mpc_intsrc(&mp_irqs[i], m);
                        mpc->length = count;
@@ -963,11 +957,14 @@ out:
        return 0;
 }
 
-static int __initdata enable_update_mptable;
+int enable_update_mptable;
 
 static int __init update_mptable_setup(char *str)
 {
        enable_update_mptable = 1;
+#ifdef CONFIG_PCI
+       pci_routeirq = 1;
+#endif
        return 0;
 }
 early_param("update_mptable", update_mptable_setup);
@@ -980,6 +977,9 @@ static int __initdata alloc_mptable;
 static int __init parse_alloc_mptable_opt(char *p)
 {
        enable_update_mptable = 1;
+#ifdef CONFIG_PCI
+       pci_routeirq = 1;
+#endif
        alloc_mptable = 1;
        if (!p)
                return 0;
index 9faf43bea3361cf178f53942e8f37a8842737afc..70ec9b951d76e0eb21a79f124b9adebe8a4b60be 100644 (file)
@@ -248,18 +248,16 @@ static DEFINE_PER_CPU(enum paravirt_lazy_mode, paravirt_lazy_mode) = PARAVIRT_LA
 
 static inline void enter_lazy(enum paravirt_lazy_mode mode)
 {
-       BUG_ON(__get_cpu_var(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE);
-       BUG_ON(preemptible());
+       BUG_ON(percpu_read(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE);
 
-       __get_cpu_var(paravirt_lazy_mode) = mode;
+       percpu_write(paravirt_lazy_mode, mode);
 }
 
-void paravirt_leave_lazy(enum paravirt_lazy_mode mode)
+static void leave_lazy(enum paravirt_lazy_mode mode)
 {
-       BUG_ON(__get_cpu_var(paravirt_lazy_mode) != mode);
-       BUG_ON(preemptible());
+       BUG_ON(percpu_read(paravirt_lazy_mode) != mode);
 
-       __get_cpu_var(paravirt_lazy_mode) = PARAVIRT_LAZY_NONE;
+       percpu_write(paravirt_lazy_mode, PARAVIRT_LAZY_NONE);
 }
 
 void paravirt_enter_lazy_mmu(void)
@@ -269,22 +267,36 @@ void paravirt_enter_lazy_mmu(void)
 
 void paravirt_leave_lazy_mmu(void)
 {
-       paravirt_leave_lazy(PARAVIRT_LAZY_MMU);
+       leave_lazy(PARAVIRT_LAZY_MMU);
 }
 
-void paravirt_enter_lazy_cpu(void)
+void paravirt_start_context_switch(struct task_struct *prev)
 {
+       BUG_ON(preemptible());
+
+       if (percpu_read(paravirt_lazy_mode) == PARAVIRT_LAZY_MMU) {
+               arch_leave_lazy_mmu_mode();
+               set_ti_thread_flag(task_thread_info(prev), TIF_LAZY_MMU_UPDATES);
+       }
        enter_lazy(PARAVIRT_LAZY_CPU);
 }
 
-void paravirt_leave_lazy_cpu(void)
+void paravirt_end_context_switch(struct task_struct *next)
 {
-       paravirt_leave_lazy(PARAVIRT_LAZY_CPU);
+       BUG_ON(preemptible());
+
+       leave_lazy(PARAVIRT_LAZY_CPU);
+
+       if (test_and_clear_ti_thread_flag(task_thread_info(next), TIF_LAZY_MMU_UPDATES))
+               arch_enter_lazy_mmu_mode();
 }
 
 enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
 {
-       return __get_cpu_var(paravirt_lazy_mode);
+       if (in_interrupt())
+               return PARAVIRT_LAZY_NONE;
+
+       return percpu_read(paravirt_lazy_mode);
 }
 
 void arch_flush_lazy_mmu_mode(void)
@@ -292,7 +304,6 @@ void arch_flush_lazy_mmu_mode(void)
        preempt_disable();
 
        if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
-               WARN_ON(preempt_count() == 1);
                arch_leave_lazy_mmu_mode();
                arch_enter_lazy_mmu_mode();
        }
@@ -300,19 +311,6 @@ void arch_flush_lazy_mmu_mode(void)
        preempt_enable();
 }
 
-void arch_flush_lazy_cpu_mode(void)
-{
-       preempt_disable();
-
-       if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_CPU) {
-               WARN_ON(preempt_count() == 1);
-               arch_leave_lazy_cpu_mode();
-               arch_enter_lazy_cpu_mode();
-       }
-
-       preempt_enable();
-}
-
 struct pv_info pv_info = {
        .name = "bare hardware",
        .paravirt_enabled = 0,
@@ -404,10 +402,8 @@ struct pv_cpu_ops pv_cpu_ops = {
        .set_iopl_mask = native_set_iopl_mask,
        .io_delay = native_io_delay,
 
-       .lazy_mode = {
-               .enter = paravirt_nop,
-               .leave = paravirt_nop,
-       },
+       .start_context_switch = paravirt_nop,
+       .end_context_switch = paravirt_nop,
 };
 
 struct pv_apic_ops pv_apic_ops = {
index 755c21e906f3f04821755c703bb99e26b118e0f7..971a3bec47a8644fdd3cbbcebb833a0ad2cc3044 100644 (file)
@@ -186,37 +186,6 @@ static struct cal_chipset_ops calioc2_chip_ops = {
 
 static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };
 
-/* enable this to stress test the chip's TCE cache */
-#ifdef CONFIG_IOMMU_DEBUG
-static int debugging = 1;
-
-static inline unsigned long verify_bit_range(unsigned long* bitmap,
-       int expected, unsigned long start, unsigned long end)
-{
-       unsigned long idx = start;
-
-       BUG_ON(start >= end);
-
-       while (idx < end) {
-               if (!!test_bit(idx, bitmap) != expected)
-                       return idx;
-               ++idx;
-       }
-
-       /* all bits have the expected value */
-       return ~0UL;
-}
-#else /* debugging is disabled */
-static int debugging;
-
-static inline unsigned long verify_bit_range(unsigned long* bitmap,
-       int expected, unsigned long start, unsigned long end)
-{
-       return ~0UL;
-}
-
-#endif /* CONFIG_IOMMU_DEBUG */
-
 static inline int translation_enabled(struct iommu_table *tbl)
 {
        /* only PHBs with translation enabled have an IOMMU table */
@@ -228,7 +197,6 @@ static void iommu_range_reserve(struct iommu_table *tbl,
 {
        unsigned long index;
        unsigned long end;
-       unsigned long badbit;
        unsigned long flags;
 
        index = start_addr >> PAGE_SHIFT;
@@ -243,14 +211,6 @@ static void iommu_range_reserve(struct iommu_table *tbl,
 
        spin_lock_irqsave(&tbl->it_lock, flags);
 
-       badbit = verify_bit_range(tbl->it_map, 0, index, end);
-       if (badbit != ~0UL) {
-               if (printk_ratelimit())
-                       printk(KERN_ERR "Calgary: entry already allocated at "
-                              "0x%lx tbl %p dma 0x%lx npages %u\n",
-                              badbit, tbl, start_addr, npages);
-       }
-
        iommu_area_reserve(tbl->it_map, index, npages);
 
        spin_unlock_irqrestore(&tbl->it_lock, flags);
@@ -326,7 +286,6 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
        unsigned int npages)
 {
        unsigned long entry;
-       unsigned long badbit;
        unsigned long badend;
        unsigned long flags;
 
@@ -346,14 +305,6 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
 
        spin_lock_irqsave(&tbl->it_lock, flags);
 
-       badbit = verify_bit_range(tbl->it_map, 1, entry, entry + npages);
-       if (badbit != ~0UL) {
-               if (printk_ratelimit())
-                       printk(KERN_ERR "Calgary: bit is off at 0x%lx "
-                              "tbl %p dma 0x%Lx entry 0x%lx npages %u\n",
-                              badbit, tbl, dma_addr, entry, npages);
-       }
-
        iommu_area_free(tbl->it_map, entry, npages);
 
        spin_unlock_irqrestore(&tbl->it_lock, flags);
@@ -1488,9 +1439,8 @@ void __init detect_calgary(void)
                iommu_detected = 1;
                calgary_detected = 1;
                printk(KERN_INFO "PCI-DMA: Calgary IOMMU detected.\n");
-               printk(KERN_INFO "PCI-DMA: Calgary TCE table spec is %d, "
-                      "CONFIG_IOMMU_DEBUG is %s.\n", specified_table_size,
-                      debugging ? "enabled" : "disabled");
+               printk(KERN_INFO "PCI-DMA: Calgary TCE table spec is %d\n",
+                      specified_table_size);
 
                /* swiotlb for devices that aren't behind the Calgary. */
                if (max_pfn > MAX_DMA32_PFN)
index b284b58c035ccdd8fc850604cced3557ae7de2c5..cfd9f90638967e03277ad510625905213322bfd4 100644 (file)
@@ -144,48 +144,21 @@ static void flush_gart(void)
 }
 
 #ifdef CONFIG_IOMMU_LEAK
-
-#define SET_LEAK(x)                                                    \
-       do {                                                            \
-               if (iommu_leak_tab)                                     \
-                       iommu_leak_tab[x] = __builtin_return_address(0);\
-       } while (0)
-
-#define CLEAR_LEAK(x)                                                  \
-       do {                                                            \
-               if (iommu_leak_tab)                                     \
-                       iommu_leak_tab[x] = NULL;                       \
-       } while (0)
-
 /* Debugging aid for drivers that don't free their IOMMU tables */
-static void **iommu_leak_tab;
 static int leak_trace;
 static int iommu_leak_pages = 20;
 
 static void dump_leak(void)
 {
-       int i;
        static int dump;
 
-       if (dump || !iommu_leak_tab)
+       if (dump)
                return;
        dump = 1;
-       show_stack(NULL, NULL);
 
-       /* Very crude. dump some from the end of the table too */
-       printk(KERN_DEBUG "Dumping %d pages from end of IOMMU:\n",
-              iommu_leak_pages);
-       for (i = 0; i < iommu_leak_pages; i += 2) {
-               printk(KERN_DEBUG "%lu: ", iommu_pages-i);
-               printk_address((unsigned long) iommu_leak_tab[iommu_pages-i],
-                               0);
-               printk(KERN_CONT "%c", (i+1)%2 == 0 ? '\n' : ' ');
-       }
-       printk(KERN_DEBUG "\n");
+       show_stack(NULL, NULL);
+       debug_dma_dump_mappings(NULL);
 }
-#else
-# define SET_LEAK(x)
-# define CLEAR_LEAK(x)
 #endif
 
 static void iommu_full(struct device *dev, size_t size, int dir)
@@ -248,7 +221,6 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem,
 
        for (i = 0; i < npages; i++) {
                iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem);
-               SET_LEAK(iommu_page + i);
                phys_mem += PAGE_SIZE;
        }
        return iommu_bus_base + iommu_page*PAGE_SIZE + (phys_mem & ~PAGE_MASK);
@@ -294,7 +266,6 @@ static void gart_unmap_page(struct device *dev, dma_addr_t dma_addr,
        npages = iommu_num_pages(dma_addr, size, PAGE_SIZE);
        for (i = 0; i < npages; i++) {
                iommu_gatt_base[iommu_page + i] = gart_unmapped_entry;
-               CLEAR_LEAK(iommu_page + i);
        }
        free_iommu(iommu_page, npages);
 }
@@ -377,7 +348,6 @@ static int __dma_map_cont(struct device *dev, struct scatterlist *start,
                pages = iommu_num_pages(s->offset, s->length, PAGE_SIZE);
                while (pages--) {
                        iommu_gatt_base[iommu_page] = GPTE_ENCODE(addr);
-                       SET_LEAK(iommu_page);
                        addr += PAGE_SIZE;
                        iommu_page++;
                }
@@ -688,8 +658,6 @@ static __init int init_k8_gatt(struct agp_kern_info *info)
 
        agp_gatt_table = gatt;
 
-       enable_gart_translations();
-
        error = sysdev_class_register(&gart_sysdev_class);
        if (!error)
                error = sysdev_register(&device_gart);
@@ -801,11 +769,12 @@ void __init gart_iommu_init(void)
 
 #ifdef CONFIG_IOMMU_LEAK
        if (leak_trace) {
-               iommu_leak_tab = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
-                                 get_order(iommu_pages*sizeof(void *)));
-               if (!iommu_leak_tab)
+               int ret;
+
+               ret = dma_debug_resize_entries(iommu_pages);
+               if (ret)
                        printk(KERN_DEBUG
-                              "PCI-DMA: Cannot allocate leak trace area\n");
+                              "PCI-DMA: Cannot trace all the entries\n");
        }
 #endif
 
@@ -845,6 +814,14 @@ void __init gart_iommu_init(void)
         * the pages as Not-Present:
         */
        wbinvd();
+       
+       /*
+        * Now all caches are flushed and we can safely enable
+        * GART hardware.  Doing it early leaves the possibility
+        * of stale cache entries that can lead to GART PTE
+        * errors.
+        */
+       enable_gart_translations();
 
        /*
         * Try to workaround a bug (thanks to BenH):
index 221a3853e2684b111c36669ee688f62ba51cdb10..a1712f2b50f1b974a1a346bd4d8db1ec21f02068 100644 (file)
@@ -28,7 +28,7 @@ dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr)
        return paddr;
 }
 
-phys_addr_t swiotlb_bus_to_phys(dma_addr_t baddr)
+phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr)
 {
        return baddr;
 }
index ca989158e847936e893c7110b4a328ea1549d452..3bb2be1649bddb5b3ba9870553b72ce73e41b460 100644 (file)
@@ -8,12 +8,15 @@
 #include <linux/module.h>
 #include <linux/pm.h>
 #include <linux/clockchips.h>
+#include <linux/random.h>
 #include <trace/power.h>
 #include <asm/system.h>
 #include <asm/apic.h>
+#include <asm/syscalls.h>
 #include <asm/idle.h>
 #include <asm/uaccess.h>
 #include <asm/i387.h>
+#include <asm/ds.h>
 
 unsigned long idle_halt;
 EXPORT_SYMBOL(idle_halt);
@@ -45,6 +48,8 @@ void free_thread_xstate(struct task_struct *tsk)
                kmem_cache_free(task_xstate_cachep, tsk->thread.xstate);
                tsk->thread.xstate = NULL;
        }
+
+       WARN(tsk->thread.ds_ctx, "leaking DS context\n");
 }
 
 void free_thread_info(struct thread_info *ti)
@@ -83,8 +88,6 @@ void exit_thread(void)
                put_cpu();
                kfree(bp);
        }
-
-       ds_exit_thread(current);
 }
 
 void flush_thread(void)
@@ -613,3 +616,16 @@ static int __init idle_setup(char *str)
 }
 early_param("idle", idle_setup);
 
+unsigned long arch_align_stack(unsigned long sp)
+{
+       if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+               sp -= get_random_int() % 8192;
+       return sp & ~0xf;
+}
+
+unsigned long arch_randomize_brk(struct mm_struct *mm)
+{
+       unsigned long range_end = mm->brk + 0x02000000;
+       return randomize_range(mm->brk, range_end, 0) ? : mm->brk;
+}
+
index 76f8f84043a2a4693123648d92d08c22ca7f5f25..59f4524984afacd10b456dcdca4abbc2237d7ecb 100644 (file)
@@ -9,8 +9,6 @@
  * This file handles the architecture-dependent parts of process handling..
  */
 
-#include <stdarg.h>
-
 #include <linux/stackprotector.h>
 #include <linux/cpu.h>
 #include <linux/errno.h>
@@ -33,7 +31,6 @@
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
-#include <linux/random.h>
 #include <linux/personality.h>
 #include <linux/tick.h>
 #include <linux/percpu.h>
@@ -290,7 +287,8 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
                p->thread.io_bitmap_max = 0;
        }
 
-       ds_copy_thread(p, current);
+       clear_tsk_thread_flag(p, TIF_DS_AREA_MSR);
+       p->thread.ds_ctx = NULL;
 
        clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR);
        p->thread.debugctlmsr = 0;
@@ -407,7 +405,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
         * done before math_state_restore, so the TS bit is up
         * to date.
         */
-       arch_leave_lazy_cpu_mode();
+       arch_end_context_switch(next_p);
 
        /* If the task has used fpu the last 5 timeslices, just do a full
         * restore of the math state immediately to avoid the trap; the
@@ -497,15 +495,3 @@ unsigned long get_wchan(struct task_struct *p)
        return 0;
 }
 
-unsigned long arch_align_stack(unsigned long sp)
-{
-       if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
-               sp -= get_random_int() % 8192;
-       return sp & ~0xf;
-}
-
-unsigned long arch_randomize_brk(struct mm_struct *mm)
-{
-       unsigned long range_end = mm->brk + 0x02000000;
-       return randomize_range(mm->brk, range_end, 0) ? : mm->brk;
-}
index b751a41392b1b997d3c9a3235ba85b2372bdf7a3..ebefb5407b9d36f5ccbb1c458708fb8a647ff19b 100644 (file)
@@ -14,8 +14,6 @@
  * This file handles the architecture-dependent parts of process handling..
  */
 
-#include <stdarg.h>
-
 #include <linux/stackprotector.h>
 #include <linux/cpu.h>
 #include <linux/errno.h>
@@ -32,7 +30,6 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/ptrace.h>
-#include <linux/random.h>
 #include <linux/notifier.h>
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
@@ -335,7 +332,8 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
                        goto out;
        }
 
-       ds_copy_thread(p, me);
+       clear_tsk_thread_flag(p, TIF_DS_AREA_MSR);
+       p->thread.ds_ctx = NULL;
 
        clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR);
        p->thread.debugctlmsr = 0;
@@ -428,7 +426,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
         * done before math_state_restore, so the TS bit is up
         * to date.
         */
-       arch_leave_lazy_cpu_mode();
+       arch_end_context_switch(next_p);
 
        /*
         * Switch FS and GS.
@@ -660,15 +658,3 @@ long sys_arch_prctl(int code, unsigned long addr)
        return do_arch_prctl(current, code, addr);
 }
 
-unsigned long arch_align_stack(unsigned long sp)
-{
-       if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
-               sp -= get_random_int() % 8192;
-       return sp & ~0xf;
-}
-
-unsigned long arch_randomize_brk(struct mm_struct *mm)
-{
-       unsigned long range_end = mm->brk + 0x02000000;
-       return randomize_range(mm->brk, range_end, 0) ? : mm->brk;
-}
index 23b7c8f017e2afa74194c81c7720724a2604751b..09ecbde91c1354e036751f71e2d5612057fe3626 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/audit.h>
 #include <linux/seccomp.h>
 #include <linux/signal.h>
+#include <linux/workqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -578,17 +579,130 @@ static int ioperm_get(struct task_struct *target,
 }
 
 #ifdef CONFIG_X86_PTRACE_BTS
+/*
+ * A branch trace store context.
+ *
+ * Contexts may only be installed by ptrace_bts_config() and only for
+ * ptraced tasks.
+ *
+ * Contexts are destroyed when the tracee is detached from the tracer.
+ * The actual destruction work requires interrupts enabled, so the
+ * work is deferred and will be scheduled during __ptrace_unlink().
+ *
+ * Contexts hold an additional task_struct reference on the traced
+ * task, as well as a reference on the tracer's mm.
+ *
+ * Ptrace already holds a task_struct for the duration of ptrace operations,
+ * but since destruction is deferred, it may be executed after both
+ * tracer and tracee exited.
+ */
+struct bts_context {
+       /* The branch trace handle. */
+       struct bts_tracer       *tracer;
+
+       /* The buffer used to store the branch trace and its size. */
+       void                    *buffer;
+       unsigned int            size;
+
+       /* The mm that paid for the above buffer. */
+       struct mm_struct        *mm;
+
+       /* The task this context belongs to. */
+       struct task_struct      *task;
+
+       /* The signal to send on a bts buffer overflow. */
+       unsigned int            bts_ovfl_signal;
+
+       /* The work struct to destroy a context. */
+       struct work_struct      work;
+};
+
+static int alloc_bts_buffer(struct bts_context *context, unsigned int size)
+{
+       void *buffer = NULL;
+       int err = -ENOMEM;
+
+       err = account_locked_memory(current->mm, current->signal->rlim, size);
+       if (err < 0)
+               return err;
+
+       buffer = kzalloc(size, GFP_KERNEL);
+       if (!buffer)
+               goto out_refund;
+
+       context->buffer = buffer;
+       context->size = size;
+       context->mm = get_task_mm(current);
+
+       return 0;
+
+ out_refund:
+       refund_locked_memory(current->mm, size);
+       return err;
+}
+
+static inline void free_bts_buffer(struct bts_context *context)
+{
+       if (!context->buffer)
+               return;
+
+       kfree(context->buffer);
+       context->buffer = NULL;
+
+       refund_locked_memory(context->mm, context->size);
+       context->size = 0;
+
+       mmput(context->mm);
+       context->mm = NULL;
+}
+
+static void free_bts_context_work(struct work_struct *w)
+{
+       struct bts_context *context;
+
+       context = container_of(w, struct bts_context, work);
+
+       ds_release_bts(context->tracer);
+       put_task_struct(context->task);
+       free_bts_buffer(context);
+       kfree(context);
+}
+
+static inline void free_bts_context(struct bts_context *context)
+{
+       INIT_WORK(&context->work, free_bts_context_work);
+       schedule_work(&context->work);
+}
+
+static inline struct bts_context *alloc_bts_context(struct task_struct *task)
+{
+       struct bts_context *context = kzalloc(sizeof(*context), GFP_KERNEL);
+       if (context) {
+               context->task = task;
+               task->bts = context;
+
+               get_task_struct(task);
+       }
+
+       return context;
+}
+
 static int ptrace_bts_read_record(struct task_struct *child, size_t index,
                                  struct bts_struct __user *out)
 {
+       struct bts_context *context;
        const struct bts_trace *trace;
        struct bts_struct bts;
        const unsigned char *at;
        int error;
 
-       trace = ds_read_bts(child->bts);
+       context = child->bts;
+       if (!context)
+               return -ESRCH;
+
+       trace = ds_read_bts(context->tracer);
        if (!trace)
-               return -EPERM;
+               return -ESRCH;
 
        at = trace->ds.top - ((index + 1) * trace->ds.size);
        if ((void *)at < trace->ds.begin)
@@ -597,7 +711,7 @@ static int ptrace_bts_read_record(struct task_struct *child, size_t index,
        if (!trace->read)
                return -EOPNOTSUPP;
 
-       error = trace->read(child->bts, at, &bts);
+       error = trace->read(context->tracer, at, &bts);
        if (error < 0)
                return error;
 
@@ -611,13 +725,18 @@ static int ptrace_bts_drain(struct task_struct *child,
                            long size,
                            struct bts_struct __user *out)
 {
+       struct bts_context *context;
        const struct bts_trace *trace;
        const unsigned char *at;
        int error, drained = 0;
 
-       trace = ds_read_bts(child->bts);
+       context = child->bts;
+       if (!context)
+               return -ESRCH;
+
+       trace = ds_read_bts(context->tracer);
        if (!trace)
-               return -EPERM;
+               return -ESRCH;
 
        if (!trace->read)
                return -EOPNOTSUPP;
@@ -628,9 +747,8 @@ static int ptrace_bts_drain(struct task_struct *child,
        for (at = trace->ds.begin; (void *)at < trace->ds.top;
             out++, drained++, at += trace->ds.size) {
                struct bts_struct bts;
-               int error;
 
-               error = trace->read(child->bts, at, &bts);
+               error = trace->read(context->tracer, at, &bts);
                if (error < 0)
                        return error;
 
@@ -640,35 +758,18 @@ static int ptrace_bts_drain(struct task_struct *child,
 
        memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size);
 
-       error = ds_reset_bts(child->bts);
+       error = ds_reset_bts(context->tracer);
        if (error < 0)
                return error;
 
        return drained;
 }
 
-static int ptrace_bts_allocate_buffer(struct task_struct *child, size_t size)
-{
-       child->bts_buffer = alloc_locked_buffer(size);
-       if (!child->bts_buffer)
-               return -ENOMEM;
-
-       child->bts_size = size;
-
-       return 0;
-}
-
-static void ptrace_bts_free_buffer(struct task_struct *child)
-{
-       free_locked_buffer(child->bts_buffer, child->bts_size);
-       child->bts_buffer = NULL;
-       child->bts_size = 0;
-}
-
 static int ptrace_bts_config(struct task_struct *child,
                             long cfg_size,
                             const struct ptrace_bts_config __user *ucfg)
 {
+       struct bts_context *context;
        struct ptrace_bts_config cfg;
        unsigned int flags = 0;
 
@@ -678,28 +779,33 @@ static int ptrace_bts_config(struct task_struct *child,
        if (copy_from_user(&cfg, ucfg, sizeof(cfg)))
                return -EFAULT;
 
-       if (child->bts) {
-               ds_release_bts(child->bts);
-               child->bts = NULL;
-       }
+       context = child->bts;
+       if (!context)
+               context = alloc_bts_context(child);
+       if (!context)
+               return -ENOMEM;
 
        if (cfg.flags & PTRACE_BTS_O_SIGNAL) {
                if (!cfg.signal)
                        return -EINVAL;
 
-               child->thread.bts_ovfl_signal = cfg.signal;
                return -EOPNOTSUPP;
+               context->bts_ovfl_signal = cfg.signal;
        }
 
-       if ((cfg.flags & PTRACE_BTS_O_ALLOC) &&
-           (cfg.size != child->bts_size)) {
-               int error;
+       ds_release_bts(context->tracer);
+       context->tracer = NULL;
 
-               ptrace_bts_free_buffer(child);
+       if ((cfg.flags & PTRACE_BTS_O_ALLOC) && (cfg.size != context->size)) {
+               int err;
 
-               error = ptrace_bts_allocate_buffer(child, cfg.size);
-               if (error < 0)
-                       return error;
+               free_bts_buffer(context);
+               if (!cfg.size)
+                       return 0;
+
+               err = alloc_bts_buffer(context, cfg.size);
+               if (err < 0)
+                       return err;
        }
 
        if (cfg.flags & PTRACE_BTS_O_TRACE)
@@ -708,15 +814,14 @@ static int ptrace_bts_config(struct task_struct *child,
        if (cfg.flags & PTRACE_BTS_O_SCHED)
                flags |= BTS_TIMESTAMPS;
 
-       child->bts = ds_request_bts(child, child->bts_buffer, child->bts_size,
-                                   /* ovfl = */ NULL, /* th = */ (size_t)-1,
-                                   flags);
-       if (IS_ERR(child->bts)) {
-               int error = PTR_ERR(child->bts);
-
-               ptrace_bts_free_buffer(child);
-               child->bts = NULL;
+       context->tracer =
+               ds_request_bts_task(child, context->buffer, context->size,
+                                   NULL, (size_t)-1, flags);
+       if (unlikely(IS_ERR(context->tracer))) {
+               int error = PTR_ERR(context->tracer);
 
+               free_bts_buffer(context);
+               context->tracer = NULL;
                return error;
        }
 
@@ -727,20 +832,25 @@ static int ptrace_bts_status(struct task_struct *child,
                             long cfg_size,
                             struct ptrace_bts_config __user *ucfg)
 {
+       struct bts_context *context;
        const struct bts_trace *trace;
        struct ptrace_bts_config cfg;
 
+       context = child->bts;
+       if (!context)
+               return -ESRCH;
+
        if (cfg_size < sizeof(cfg))
                return -EIO;
 
-       trace = ds_read_bts(child->bts);
+       trace = ds_read_bts(context->tracer);
        if (!trace)
-               return -EPERM;
+               return -ESRCH;
 
        memset(&cfg, 0, sizeof(cfg));
-       cfg.size = trace->ds.end - trace->ds.begin;
-       cfg.signal = child->thread.bts_ovfl_signal;
-       cfg.bts_size = sizeof(struct bts_struct);
+       cfg.size        = trace->ds.end - trace->ds.begin;
+       cfg.signal      = context->bts_ovfl_signal;
+       cfg.bts_size    = sizeof(struct bts_struct);
 
        if (cfg.signal)
                cfg.flags |= PTRACE_BTS_O_SIGNAL;
@@ -759,80 +869,51 @@ static int ptrace_bts_status(struct task_struct *child,
 
 static int ptrace_bts_clear(struct task_struct *child)
 {
+       struct bts_context *context;
        const struct bts_trace *trace;
 
-       trace = ds_read_bts(child->bts);
+       context = child->bts;
+       if (!context)
+               return -ESRCH;
+
+       trace = ds_read_bts(context->tracer);
        if (!trace)
-               return -EPERM;
+               return -ESRCH;
 
        memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size);
 
-       return ds_reset_bts(child->bts);
+       return ds_reset_bts(context->tracer);
 }
 
 static int ptrace_bts_size(struct task_struct *child)
 {
+       struct bts_context *context;
        const struct bts_trace *trace;
 
-       trace = ds_read_bts(child->bts);
+       context = child->bts;
+       if (!context)
+               return -ESRCH;
+
+       trace = ds_read_bts(context->tracer);
        if (!trace)
-               return -EPERM;
+               return -ESRCH;
 
        return (trace->ds.top - trace->ds.begin) / trace->ds.size;
 }
 
-static void ptrace_bts_fork(struct task_struct *tsk)
-{
-       tsk->bts = NULL;
-       tsk->bts_buffer = NULL;
-       tsk->bts_size = 0;
-       tsk->thread.bts_ovfl_signal = 0;
-}
-
-static void ptrace_bts_untrace(struct task_struct *child)
+/*
+ * Called from __ptrace_unlink() after the child has been moved back
+ * to its original parent.
+ */
+void ptrace_bts_untrace(struct task_struct *child)
 {
        if (unlikely(child->bts)) {
-               ds_release_bts(child->bts);
+               free_bts_context(child->bts);
                child->bts = NULL;
-
-               /* We cannot update total_vm and locked_vm since
-                  child's mm is already gone. But we can reclaim the
-                  memory. */
-               kfree(child->bts_buffer);
-               child->bts_buffer = NULL;
-               child->bts_size = 0;
        }
 }
-
-static void ptrace_bts_detach(struct task_struct *child)
-{
-       /*
-        * Ptrace_detach() races with ptrace_untrace() in case
-        * the child dies and is reaped by another thread.
-        *
-        * We only do the memory accounting at this point and
-        * leave the buffer deallocation and the bts tracer
-        * release to ptrace_bts_untrace() which will be called
-        * later on with tasklist_lock held.
-        */
-       release_locked_buffer(child->bts_buffer, child->bts_size);
-}
-#else
-static inline void ptrace_bts_fork(struct task_struct *tsk) {}
-static inline void ptrace_bts_detach(struct task_struct *child) {}
-static inline void ptrace_bts_untrace(struct task_struct *child) {}
 #endif /* CONFIG_X86_PTRACE_BTS */
 
-void x86_ptrace_fork(struct task_struct *child, unsigned long clone_flags)
-{
-       ptrace_bts_fork(child);
-}
-
-void x86_ptrace_untrace(struct task_struct *child)
-{
-       ptrace_bts_untrace(child);
-}
-
 /*
  * Called by kernel/ptrace.c when detaching..
  *
@@ -844,7 +925,6 @@ void ptrace_disable(struct task_struct *child)
 #ifdef TIF_SYSCALL_EMU
        clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
 #endif
-       ptrace_bts_detach(child);
 }
 
 #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
index 7563b31b4f0349f45bf324053a67ecb506a4fced..af71d06624bf5b70b5173ba29238c40b6c21c801 100644 (file)
@@ -491,5 +491,42 @@ void force_hpet_resume(void)
                break;
        }
 }
+#endif
+
+#if defined(CONFIG_PCI) && defined(CONFIG_NUMA)
+/* Set correct numa_node information for AMD NB functions */
+static void __init quirk_amd_nb_node(struct pci_dev *dev)
+{
+       struct pci_dev *nb_ht;
+       unsigned int devfn;
+       u32 val;
+
+       devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0);
+       nb_ht = pci_get_slot(dev->bus, devfn);
+       if (!nb_ht)
+               return;
+
+       pci_read_config_dword(nb_ht, 0x60, &val);
+       set_dev_node(&dev->dev, val & 7);
+       pci_dev_put(dev);
+}
 
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB,
+                       quirk_amd_nb_node);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
+                       quirk_amd_nb_node);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MEMCTL,
+                       quirk_amd_nb_node);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC,
+                       quirk_amd_nb_node);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_HT,
+                       quirk_amd_nb_node);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MAP,
+                       quirk_amd_nb_node);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_DRAM,
+                       quirk_amd_nb_node);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC,
+                       quirk_amd_nb_node);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_LINK,
+                       quirk_amd_nb_node);
 #endif
index 667188e0b5a0bfac320d69a0f734dda03b5bee88..d2d1ce8170f06c8573ac022f4e49dfc59a371c9b 100644 (file)
@@ -192,6 +192,15 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
                },
        },
+       {   /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
+               .callback = set_bios_reboot,
+               .ident = "Dell OptiPlex 360",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"),
+                       DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
+               },
+       },
        {       /* Handle problems with rebooting on Dell 2400's */
                .callback = set_bios_reboot,
                .ident = "Dell PowerEdge 2400",
index b4158439bf634d254852cceab2c30d26f943f7ea..d1c636bf31a71018d73f7e36616d2c7d533707ea 100644 (file)
 #define ARCH_SETUP
 #endif
 
+/*
+ * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries.
+ * The direct mapping extends to max_pfn_mapped, so that we can directly access
+ * apertures, ACPI and other tables without having to play with fixmaps.
+ */
+unsigned long max_low_pfn_mapped;
+unsigned long max_pfn_mapped;
+
 RESERVE_BRK(dmi_alloc, 65536);
 
 unsigned int boot_cpu_id __read_mostly;
@@ -214,8 +222,8 @@ unsigned long mmu_cr4_features;
 unsigned long mmu_cr4_features = X86_CR4_PAE;
 #endif
 
-/* Boot loader ID as an integer, for the benefit of proc_dointvec */
-int bootloader_type;
+/* Boot loader ID and version as integers, for the benefit of proc_dointvec */
+int bootloader_type, bootloader_version;
 
 /*
  * Setup options
@@ -706,6 +714,12 @@ void __init setup_arch(char **cmdline_p)
 #endif
        saved_video_mode = boot_params.hdr.vid_mode;
        bootloader_type = boot_params.hdr.type_of_loader;
+       if ((bootloader_type >> 4) == 0xe) {
+               bootloader_type &= 0xf;
+               bootloader_type |= (boot_params.hdr.ext_loader_type+0x10) << 4;
+       }
+       bootloader_version  = bootloader_type & 0xf;
+       bootloader_version |= boot_params.hdr.ext_loader_ver << 4;
 
 #ifdef CONFIG_BLK_DEV_RAM
        rd_image_start = boot_params.hdr.ram_size & RAMDISK_IMAGE_START_MASK;
@@ -854,12 +868,16 @@ void __init setup_arch(char **cmdline_p)
                max_low_pfn = max_pfn;
 
        high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
+       max_pfn_mapped = KERNEL_IMAGE_SIZE >> PAGE_SHIFT;
 #endif
 
 #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
        setup_bios_corruption_check();
 #endif
 
+       printk(KERN_DEBUG "initial memory mapped : 0 - %08lx\n",
+                       max_pfn_mapped<<PAGE_SHIFT);
+
        reserve_brk();
 
        /* max_pfn_mapped is updated here */
@@ -996,24 +1014,6 @@ void __init setup_arch(char **cmdline_p)
 
 #ifdef CONFIG_X86_32
 
-/**
- * x86_quirk_pre_intr_init - initialisation prior to setting up interrupt vectors
- *
- * Description:
- *     Perform any necessary interrupt initialisation prior to setting up
- *     the "ordinary" interrupt call gates.  For legacy reasons, the ISA
- *     interrupts should be initialised here if the machine emulates a PC
- *     in any way.
- **/
-void __init x86_quirk_pre_intr_init(void)
-{
-       if (x86_quirks->arch_pre_intr_init) {
-               if (x86_quirks->arch_pre_intr_init())
-                       return;
-       }
-       init_ISA_irqs();
-}
-
 /**
  * x86_quirk_intr_init - post gate setup interrupt initialisation
  *
index 8f0e13be36b31d1a80c94dec2692504d2a9a86db..9c3f0823e6aa00ea93bec0babdfd2c0b19971d13 100644 (file)
@@ -425,6 +425,14 @@ void __init setup_per_cpu_areas(void)
        early_per_cpu_ptr(x86_cpu_to_node_map) = NULL;
 #endif
 
+#if defined(CONFIG_X86_64) && defined(CONFIG_NUMA)
+       /*
+        * make sure boot cpu node_number is right, when boot cpu is on the
+        * node that doesn't have mem installed
+        */
+       per_cpu(node_number, boot_cpu_id) = cpu_to_node(boot_cpu_id);
+#endif
+
        /* Setup node to cpumask map */
        setup_node_to_cpumask_map();
 
index 13f33ea8ccaaf1ae8e23cc2a39f57d84d6d3c910..28f5fb495a669e9b6843daf33a37baaac512fad7 100644 (file)
@@ -172,6 +172,9 @@ void smp_reschedule_interrupt(struct pt_regs *regs)
 {
        ack_APIC_irq();
        inc_irq_stat(irq_resched_count);
+       /*
+        * KVM uses this interrupt to force a cpu out of guest mode
+        */
 }
 
 void smp_call_function_interrupt(struct pt_regs *regs)
@@ -193,19 +196,19 @@ void smp_call_function_single_interrupt(struct pt_regs *regs)
 }
 
 struct smp_ops smp_ops = {
-       .smp_prepare_boot_cpu = native_smp_prepare_boot_cpu,
-       .smp_prepare_cpus = native_smp_prepare_cpus,
-       .smp_cpus_done = native_smp_cpus_done,
+       .smp_prepare_boot_cpu   = native_smp_prepare_boot_cpu,
+       .smp_prepare_cpus       = native_smp_prepare_cpus,
+       .smp_cpus_done          = native_smp_cpus_done,
 
-       .smp_send_stop = native_smp_send_stop,
-       .smp_send_reschedule = native_smp_send_reschedule,
+       .smp_send_stop          = native_smp_send_stop,
+       .smp_send_reschedule    = native_smp_send_reschedule,
 
-       .cpu_up = native_cpu_up,
-       .cpu_die = native_cpu_die,
-       .cpu_disable = native_cpu_disable,
-       .play_dead = native_play_dead,
+       .cpu_up                 = native_cpu_up,
+       .cpu_die                = native_cpu_die,
+       .cpu_disable            = native_cpu_disable,
+       .play_dead              = native_play_dead,
 
-       .send_call_func_ipi = native_send_call_func_ipi,
+       .send_call_func_ipi     = native_send_call_func_ipi,
        .send_call_func_single_ipi = native_send_call_func_single_ipi,
 };
 EXPORT_SYMBOL_GPL(smp_ops);
index 58d24ef917d8b46e7c7faedc4dd3fc79266ad0cb..7c80007ea5f7fb28ce9e61c4569f3c3432981b1d 100644 (file)
@@ -504,7 +504,7 @@ void __inquire_remote_apic(int apicid)
  * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
  * won't ... remember to clear down the APIC, etc later.
  */
-int __devinit
+int __cpuinit
 wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip)
 {
        unsigned long send_status, accept_status = 0;
@@ -538,7 +538,7 @@ wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip)
        return (send_status | accept_status);
 }
 
-int __devinit
+static int __cpuinit
 wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
 {
        unsigned long send_status, accept_status = 0;
@@ -822,10 +822,12 @@ do_rest:
        /* mark "stuck" area as not stuck */
        *((volatile unsigned long *)trampoline_base) = 0;
 
-       /*
-        * Cleanup possible dangling ends...
-        */
-       smpboot_restore_warm_reset_vector();
+       if (get_uv_system_type() != UV_NON_UNIQUE_APIC) {
+               /*
+                * Cleanup possible dangling ends...
+                */
+               smpboot_restore_warm_reset_vector();
+       }
 
        return boot_error;
 }
@@ -990,10 +992,12 @@ static int __init smp_sanity_check(unsigned max_cpus)
         */
        if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) &&
            !cpu_has_apic) {
-               printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
-                       boot_cpu_physical_apicid);
-               printk(KERN_ERR "... forcing use of dummy APIC emulation."
+               if (!disable_apic) {
+                       pr_err("BIOS bug, local APIC #%d not detected!...\n",
+                               boot_cpu_physical_apicid);
+                       pr_err("... forcing use of dummy APIC emulation."
                                "(tell your hw vendor)\n");
+               }
                smpboot_clear_io_apic();
                arch_disable_smp_support();
                return -1;
index f7bddc2e37d1bbf19a86f03b9e3a3a0da70ab199..4aaf7e48394fb562343f27d811e7a9f329be2b76 100644 (file)
@@ -20,7 +20,7 @@ save_stack_warning_symbol(void *data, char *msg, unsigned long symbol)
 
 static int save_stack_stack(void *data, char *name)
 {
-       return -1;
+       return 0;
 }
 
 static void save_stack_address(void *data, unsigned long addr, int reliable)
index ff5c8736b491b8ff2c4835c5a19a51ad63633de1..734f92c02dde0f7dbf4564907dfb920512ee908d 100644 (file)
@@ -334,3 +334,4 @@ ENTRY(sys_call_table)
        .long sys_inotify_init1
        .long sys_preadv
        .long sys_pwritev
+       .long sys_rt_tgsigqueueinfo     /* 335 */
index 8c7b03b0cfcb47b1585187e95a67890137218c5d..124d40c575df376e989d5b00229fda865f0bb682 100644 (file)
@@ -715,7 +715,12 @@ uv_activation_descriptor_init(int node, int pnode)
        struct bau_desc *adp;
        struct bau_desc *ad2;
 
-       adp = (struct bau_desc *)kmalloc_node(16384, GFP_KERNEL, node);
+       /*
+        * each bau_desc is 64 bytes; there are 8 (UV_ITEMS_PER_DESCRIPTOR)
+        * per cpu; and up to 32 (UV_ADP_SIZE) cpu's per blade
+        */
+       adp = (struct bau_desc *)kmalloc_node(sizeof(struct bau_desc)*
+               UV_ADP_SIZE*UV_ITEMS_PER_DESCRIPTOR, GFP_KERNEL, node);
        BUG_ON(!adp);
 
        pa = uv_gpa(adp); /* need the real nasid*/
@@ -729,7 +734,13 @@ uv_activation_descriptor_init(int node, int pnode)
                                      (n << UV_DESC_BASE_PNODE_SHIFT | m));
        }
 
-       for (i = 0, ad2 = adp; i < UV_ACTIVATION_DESCRIPTOR_SIZE; i++, ad2++) {
+       /*
+        * initializing all 8 (UV_ITEMS_PER_DESCRIPTOR) descriptors for each
+        * cpu even though we only use the first one; one descriptor can
+        * describe a broadcast to 256 nodes.
+        */
+       for (i = 0, ad2 = adp; i < (UV_ADP_SIZE*UV_ITEMS_PER_DESCRIPTOR);
+               i++, ad2++) {
                memset(ad2, 0, sizeof(struct bau_desc));
                ad2->header.sw_ack_flag = 1;
                /*
index a1d288327ff0ff0f152241bf296c742778f61e00..ede024531f8facbc53fdfd4c82b687ee2050ac72 100644 (file)
@@ -839,9 +839,6 @@ asmlinkage void math_state_restore(void)
        }
 
        clts();                         /* Allow maths ops (or we recurse) */
-#ifdef CONFIG_X86_32
-       restore_fpu(tsk);
-#else
        /*
         * Paranoid restore. send a SIGSEGV if we fail to restore the state.
         */
@@ -850,7 +847,7 @@ asmlinkage void math_state_restore(void)
                force_sig(SIGSEGV, tsk);
                return;
        }
-#endif
+
        thread->status |= TS_USEDFPU;   /* So we fnsave on switch_to() */
        tsk->fpu_counter++;
 }
@@ -969,11 +966,8 @@ void __init trap_init(void)
        for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)
                set_bit(i, used_vectors);
 
-#ifdef CONFIG_X86_64
        set_bit(IA32_SYSCALL_VECTOR, used_vectors);
-#else
-       set_bit(SYSCALL_VECTOR, used_vectors);
-#endif
+
        /*
         * Should be a barrier for any external CPU state:
         */
index d57de05dc43093e0831ebb544a2baddf3d72f184..3e1c057e98fe039325eed2056d8960fa52f023c4 100644 (file)
@@ -384,13 +384,13 @@ unsigned long native_calibrate_tsc(void)
 {
        u64 tsc1, tsc2, delta, ref1, ref2;
        unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX;
-       unsigned long flags, latch, ms, fast_calibrate, tsc_khz;
+       unsigned long flags, latch, ms, fast_calibrate, hv_tsc_khz;
        int hpet = is_hpet_enabled(), i, loopmin;
 
-       tsc_khz = get_hypervisor_tsc_freq();
-       if (tsc_khz) {
+       hv_tsc_khz = get_hypervisor_tsc_freq();
+       if (hv_tsc_khz) {
                printk(KERN_INFO "TSC: Frequency read from the hypervisor\n");
-               return tsc_khz;
+               return hv_tsc_khz;
        }
 
        local_irq_save(flags);
@@ -710,7 +710,16 @@ static cycle_t read_tsc(struct clocksource *cs)
 #ifdef CONFIG_X86_64
 static cycle_t __vsyscall_fn vread_tsc(void)
 {
-       cycle_t ret = (cycle_t)vget_cycles();
+       cycle_t ret;
+
+       /*
+        * Surround the RDTSC by barriers, to make sure it's not
+        * speculated to outside the seqlock critical section and
+        * does not cause time warps:
+        */
+       rdtsc_barrier();
+       ret = (cycle_t)vget_cycles();
+       rdtsc_barrier();
 
        return ret >= __vsyscall_gtod_data.clock.cycle_last ?
                ret : __vsyscall_gtod_data.clock.cycle_last;
index bf36328f6ef9289c4b1a1a7d0ffd9c67878f3f32..027b5b498993b6f0606367e2803f6fc9f15dca2c 100644 (file)
@@ -34,6 +34,7 @@ static __cpuinitdata atomic_t stop_count;
  * of a critical section, to be able to prove TSC time-warps:
  */
 static __cpuinitdata raw_spinlock_t sync_lock = __RAW_SPIN_LOCK_UNLOCKED;
+
 static __cpuinitdata cycles_t last_tsc;
 static __cpuinitdata cycles_t max_warp;
 static __cpuinitdata int nr_warps;
@@ -113,13 +114,12 @@ void __cpuinit check_tsc_sync_source(int cpu)
                return;
 
        if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) {
-               printk(KERN_INFO
-                      "Skipping synchronization checks as TSC is reliable.\n");
+               pr_info("Skipping synchronization checks as TSC is reliable.\n");
                return;
        }
 
-       printk(KERN_INFO "checking TSC synchronization [CPU#%d -> CPU#%d]:",
-                         smp_processor_id(), cpu);
+       pr_info("checking TSC synchronization [CPU#%d -> CPU#%d]:",
+               smp_processor_id(), cpu);
 
        /*
         * Reset it - in case this is a second bootup:
@@ -143,8 +143,8 @@ void __cpuinit check_tsc_sync_source(int cpu)
 
        if (nr_warps) {
                printk("\n");
-               printk(KERN_WARNING "Measured %Ld cycles TSC warp between CPUs,"
-                                   " turning off TSC clock.\n", max_warp);
+               pr_warning("Measured %Ld cycles TSC warp between CPUs, "
+                          "turning off TSC clock.\n", max_warp);
                mark_tsc_unstable("check_tsc_sync_source failed");
        } else {
                printk(" passed.\n");
@@ -195,5 +195,3 @@ void __cpuinit check_tsc_sync_target(void)
        while (atomic_read(&stop_count) != cpus)
                cpu_relax();
 }
-#undef NR_LOOPS
-
index d7ac84e7fc1c73f7cfcfd8ca6b66c5abed2219ce..9c4e625390589ac69e984edded55d13d6200a031 100644 (file)
@@ -287,10 +287,9 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk
        info->regs.pt.ds = 0;
        info->regs.pt.es = 0;
        info->regs.pt.fs = 0;
-
-/* we are clearing gs later just before "jmp resume_userspace",
- * because it is not saved/restored.
- */
+#ifndef CONFIG_X86_32_LAZY_GS
+       info->regs.pt.gs = 0;
+#endif
 
 /*
  * The flags register is also special: we cannot trust that the user
@@ -318,9 +317,9 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk
        }
 
 /*
- * Save old state, set default return value (%ax) to 0
+ * Save old state, set default return value (%ax) to 0 (VM86_SIGNAL)
  */
-       info->regs32->ax = 0;
+       info->regs32->ax = VM86_SIGNAL;
        tsk->thread.saved_sp0 = tsk->thread.sp0;
        tsk->thread.saved_fs = info->regs32->fs;
        tsk->thread.saved_gs = get_user_gs(info->regs32);
@@ -343,7 +342,9 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk
        __asm__ __volatile__(
                "movl %0,%%esp\n\t"
                "movl %1,%%ebp\n\t"
+#ifdef CONFIG_X86_32_LAZY_GS
                "mov  %2, %%gs\n\t"
+#endif
                "jmp resume_userspace"
                : /* no outputs */
                :"r" (&info->regs), "r" (task_thread_info(tsk)), "r" (0));
index 95deb9f2211e98decb5572e4757bc2cc48f3da18..b263423fbe2ae971424c5bd99c112ac984413383 100644 (file)
@@ -462,22 +462,28 @@ vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip,
 }
 #endif
 
-static void vmi_enter_lazy_cpu(void)
+static void vmi_start_context_switch(struct task_struct *prev)
 {
-       paravirt_enter_lazy_cpu();
+       paravirt_start_context_switch(prev);
        vmi_ops.set_lazy_mode(2);
 }
 
+static void vmi_end_context_switch(struct task_struct *next)
+{
+       vmi_ops.set_lazy_mode(0);
+       paravirt_end_context_switch(next);
+}
+
 static void vmi_enter_lazy_mmu(void)
 {
        paravirt_enter_lazy_mmu();
        vmi_ops.set_lazy_mode(1);
 }
 
-static void vmi_leave_lazy(void)
+static void vmi_leave_lazy_mmu(void)
 {
-       paravirt_leave_lazy(paravirt_get_lazy_mode());
        vmi_ops.set_lazy_mode(0);
+       paravirt_leave_lazy_mmu();
 }
 
 static inline int __init check_vmi_rom(struct vrom_header *rom)
@@ -711,14 +717,14 @@ static inline int __init activate_vmi(void)
        para_fill(pv_cpu_ops.set_iopl_mask, SetIOPLMask);
        para_fill(pv_cpu_ops.io_delay, IODelay);
 
-       para_wrap(pv_cpu_ops.lazy_mode.enter, vmi_enter_lazy_cpu,
+       para_wrap(pv_cpu_ops.start_context_switch, vmi_start_context_switch,
                  set_lazy_mode, SetLazyMode);
-       para_wrap(pv_cpu_ops.lazy_mode.leave, vmi_leave_lazy,
+       para_wrap(pv_cpu_ops.end_context_switch, vmi_end_context_switch,
                  set_lazy_mode, SetLazyMode);
 
        para_wrap(pv_mmu_ops.lazy_mode.enter, vmi_enter_lazy_mmu,
                  set_lazy_mode, SetLazyMode);
-       para_wrap(pv_mmu_ops.lazy_mode.leave, vmi_leave_lazy,
+       para_wrap(pv_mmu_ops.lazy_mode.leave, vmi_leave_lazy_mmu,
                  set_lazy_mode, SetLazyMode);
 
        /* user and kernel flush are just handled with different flags to FlushTLB */
index 849ee611f01388684ff9102838bef8a4fe38464b..4c85b2e2bb652873da1ee5367549e070b363bf8a 100644 (file)
@@ -1,5 +1,431 @@
+/*
+ * ld script for the x86 kernel
+ *
+ * Historic 32-bit version written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * Modernisation, unification and other changes and fixes:
+ *   Copyright (C) 2007-2009  Sam Ravnborg <sam@ravnborg.org>
+ *
+ *
+ * Don't define absolute symbols until and unless you know that symbol
+ * value is should remain constant even if kernel image is relocated
+ * at run time. Absolute symbols are not relocated. If symbol value should
+ * change if kernel is relocated, make the symbol section relative and
+ * put it inside the section definition.
+ */
+
 #ifdef CONFIG_X86_32
-# include "vmlinux_32.lds.S"
+#define LOAD_OFFSET __PAGE_OFFSET
 #else
-# include "vmlinux_64.lds.S"
+#define LOAD_OFFSET __START_KERNEL_map
 #endif
+
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/page_types.h>
+#include <asm/cache.h>
+#include <asm/boot.h>
+
+#undef i386     /* in case the preprocessor is a 32bit one */
+
+OUTPUT_FORMAT(CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT)
+
+#ifdef CONFIG_X86_32
+OUTPUT_ARCH(i386)
+ENTRY(phys_startup_32)
+jiffies = jiffies_64;
+#else
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(phys_startup_64)
+jiffies_64 = jiffies;
+#endif
+
+PHDRS {
+       text PT_LOAD FLAGS(5);          /* R_E */
+       data PT_LOAD FLAGS(7);          /* RWE */
+#ifdef CONFIG_X86_64
+       user PT_LOAD FLAGS(7);          /* RWE */
+       data.init PT_LOAD FLAGS(7);     /* RWE */
+#ifdef CONFIG_SMP
+       percpu PT_LOAD FLAGS(7);        /* RWE */
+#endif
+       data.init2 PT_LOAD FLAGS(7);    /* RWE */
+#endif
+       note PT_NOTE FLAGS(0);          /* ___ */
+}
+
+SECTIONS
+{
+#ifdef CONFIG_X86_32
+        . = LOAD_OFFSET + LOAD_PHYSICAL_ADDR;
+        phys_startup_32 = startup_32 - LOAD_OFFSET;
+#else
+        . = __START_KERNEL;
+        phys_startup_64 = startup_64 - LOAD_OFFSET;
+#endif
+
+       /* Text and read-only data */
+
+       /* bootstrapping code */
+       .text.head : AT(ADDR(.text.head) - LOAD_OFFSET) {
+               _text = .;
+               *(.text.head)
+       } :text = 0x9090
+
+       /* The rest of the text */
+       .text :  AT(ADDR(.text) - LOAD_OFFSET) {
+#ifdef CONFIG_X86_32
+               /* not really needed, already page aligned */
+               . = ALIGN(PAGE_SIZE);
+               *(.text.page_aligned)
+#endif
+               . = ALIGN(8);
+               _stext = .;
+               TEXT_TEXT
+               SCHED_TEXT
+               LOCK_TEXT
+               KPROBES_TEXT
+               IRQENTRY_TEXT
+               *(.fixup)
+               *(.gnu.warning)
+               /* End of text section */
+               _etext = .;
+       } :text = 0x9090
+
+       NOTES :text :note
+
+       /* Exception table */
+       . = ALIGN(16);
+       __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
+               __start___ex_table = .;
+               *(__ex_table)
+               __stop___ex_table = .;
+       } :text = 0x9090
+
+       RODATA
+
+       /* Data */
+       . = ALIGN(PAGE_SIZE);
+       .data : AT(ADDR(.data) - LOAD_OFFSET) {
+               DATA_DATA
+               CONSTRUCTORS
+
+#ifdef CONFIG_X86_64
+               /* End of data section */
+               _edata = .;
+#endif
+       } :data
+
+#ifdef CONFIG_X86_32
+       /* 32 bit has nosave before _edata */
+       . = ALIGN(PAGE_SIZE);
+       .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) {
+               __nosave_begin = .;
+               *(.data.nosave)
+               . = ALIGN(PAGE_SIZE);
+               __nosave_end = .;
+       }
+#endif
+
+       . = ALIGN(PAGE_SIZE);
+       .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+               *(.data.page_aligned)
+               *(.data.idt)
+       }
+
+#ifdef CONFIG_X86_32
+       . = ALIGN(32);
+#else
+       . = ALIGN(PAGE_SIZE);
+       . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+#endif
+       .data.cacheline_aligned :
+               AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
+               *(.data.cacheline_aligned)
+       }
+
+       /* rarely changed data like cpu maps */
+#ifdef CONFIG_X86_32
+       . = ALIGN(32);
+#else
+       . = ALIGN(CONFIG_X86_INTERNODE_CACHE_BYTES);
+#endif
+       .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) {
+               *(.data.read_mostly)
+
+#ifdef CONFIG_X86_32
+               /* End of data section */
+               _edata = .;
+#endif
+       }
+
+#ifdef CONFIG_X86_64
+
+#define VSYSCALL_ADDR (-10*1024*1024)
+#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.read_mostly) + \
+                            SIZEOF(.data.read_mostly) + 4095) & ~(4095))
+#define VSYSCALL_VIRT_ADDR ((ADDR(.data.read_mostly) + \
+                            SIZEOF(.data.read_mostly) + 4095) & ~(4095))
+
+#define VLOAD_OFFSET (VSYSCALL_ADDR - VSYSCALL_PHYS_ADDR)
+#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET)
+
+#define VVIRT_OFFSET (VSYSCALL_ADDR - VSYSCALL_VIRT_ADDR)
+#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET)
+
+       . = VSYSCALL_ADDR;
+       .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) {
+               *(.vsyscall_0)
+       } :user
+
+       __vsyscall_0 = VSYSCALL_VIRT_ADDR;
+
+       . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+       .vsyscall_fn : AT(VLOAD(.vsyscall_fn)) {
+               *(.vsyscall_fn)
+       }
+
+       . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+       .vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data)) {
+               *(.vsyscall_gtod_data)
+       }
+
+       vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data);
+       .vsyscall_clock : AT(VLOAD(.vsyscall_clock)) {
+               *(.vsyscall_clock)
+       }
+       vsyscall_clock = VVIRT(.vsyscall_clock);
+
+
+       .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) {
+               *(.vsyscall_1)
+       }
+       .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2)) {
+               *(.vsyscall_2)
+       }
+
+       .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) {
+               *(.vgetcpu_mode)
+       }
+       vgetcpu_mode = VVIRT(.vgetcpu_mode);
+
+       . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+       .jiffies : AT(VLOAD(.jiffies)) {
+               *(.jiffies)
+       }
+       jiffies = VVIRT(.jiffies);
+
+       .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) {
+               *(.vsyscall_3)
+       }
+
+       . = VSYSCALL_VIRT_ADDR + PAGE_SIZE;
+
+#undef VSYSCALL_ADDR
+#undef VSYSCALL_PHYS_ADDR
+#undef VSYSCALL_VIRT_ADDR
+#undef VLOAD_OFFSET
+#undef VLOAD
+#undef VVIRT_OFFSET
+#undef VVIRT
+
+#endif /* CONFIG_X86_64 */
+
+       /* init_task */
+       . = ALIGN(THREAD_SIZE);
+       .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
+               *(.data.init_task)
+       }
+#ifdef CONFIG_X86_64
+        :data.init
+#endif
+
+       /*
+        * smp_locks might be freed after init
+        * start/end must be page aligned
+        */
+       . = ALIGN(PAGE_SIZE);
+       .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
+               __smp_locks = .;
+               *(.smp_locks)
+               __smp_locks_end = .;
+               . = ALIGN(PAGE_SIZE);
+       }
+
+       /* Init code and data - will be freed after init */
+       . = ALIGN(PAGE_SIZE);
+       .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
+               __init_begin = .; /* paired with __init_end */
+               _sinittext = .;
+               INIT_TEXT
+               _einittext = .;
+       }
+
+       .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {
+               INIT_DATA
+       }
+
+       . = ALIGN(16);
+       .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
+               __setup_start = .;
+               *(.init.setup)
+               __setup_end = .;
+       }
+       .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
+               __initcall_start = .;
+               INITCALLS
+               __initcall_end = .;
+       }
+
+       .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
+               __con_initcall_start = .;
+               *(.con_initcall.init)
+               __con_initcall_end = .;
+       }
+
+       .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
+               __x86_cpu_dev_start = .;
+               *(.x86_cpu_dev.init)
+               __x86_cpu_dev_end = .;
+       }
+
+       SECURITY_INIT
+
+       . = ALIGN(8);
+       .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) {
+               __parainstructions = .;
+               *(.parainstructions)
+               __parainstructions_end = .;
+       }
+
+       . = ALIGN(8);
+       .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
+               __alt_instructions = .;
+               *(.altinstructions)
+               __alt_instructions_end = .;
+       }
+
+       .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
+               *(.altinstr_replacement)
+       }
+
+       /*
+        * .exit.text is discard at runtime, not link time, to deal with
+        *  references from .altinstructions and .eh_frame
+        */
+       .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) {
+               EXIT_TEXT
+       }
+
+       .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) {
+               EXIT_DATA
+       }
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       . = ALIGN(PAGE_SIZE);
+       .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
+               __initramfs_start = .;
+               *(.init.ramfs)
+               __initramfs_end = .;
+       }
+#endif
+
+#if defined(CONFIG_X86_64) && defined(CONFIG_SMP)
+       /*
+        * percpu offsets are zero-based on SMP.  PERCPU_VADDR() changes the
+        * output PHDR, so the next output section - __data_nosave - should
+        * start another section data.init2.  Also, pda should be at the head of
+        * percpu area.  Preallocate it and define the percpu offset symbol
+        * so that it can be accessed as a percpu variable.
+        */
+       . = ALIGN(PAGE_SIZE);
+       PERCPU_VADDR(0, :percpu)
+#else
+       PERCPU(PAGE_SIZE)
+#endif
+
+       . = ALIGN(PAGE_SIZE);
+
+       /* freed after init ends here */
+       .init.end : AT(ADDR(.init.end) - LOAD_OFFSET) {
+               __init_end = .;
+       }
+
+#ifdef CONFIG_X86_64
+       .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) {
+               . = ALIGN(PAGE_SIZE);
+               __nosave_begin = .;
+               *(.data.nosave)
+               . = ALIGN(PAGE_SIZE);
+               __nosave_end = .;
+       } :data.init2
+       /* use another section data.init2, see PERCPU_VADDR() above */
+#endif
+
+       /* BSS */
+       . = ALIGN(PAGE_SIZE);
+       .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
+               __bss_start = .;
+               *(.bss.page_aligned)
+               *(.bss)
+               . = ALIGN(4);
+               __bss_stop = .;
+       }
+
+       . = ALIGN(PAGE_SIZE);
+       .brk : AT(ADDR(.brk) - LOAD_OFFSET) {
+               __brk_base = .;
+               . += 64 * 1024;         /* 64k alignment slop space */
+               *(.brk_reservation)     /* areas brk users have reserved */
+               __brk_limit = .;
+       }
+
+       .end : AT(ADDR(.end) - LOAD_OFFSET) {
+               _end = .;
+       }
+
+       /* Sections to be discarded */
+       /DISCARD/ : {
+               *(.exitcall.exit)
+               *(.eh_frame)
+               *(.discard)
+       }
+
+        STABS_DEBUG
+        DWARF_DEBUG
+}
+
+
+#ifdef CONFIG_X86_32
+ASSERT((_end - LOAD_OFFSET <= KERNEL_IMAGE_SIZE),
+        "kernel image bigger than KERNEL_IMAGE_SIZE")
+#else
+/*
+ * Per-cpu symbols which need to be offset from __per_cpu_load
+ * for the boot processor.
+ */
+#define INIT_PER_CPU(x) init_per_cpu__##x = per_cpu__##x + __per_cpu_load
+INIT_PER_CPU(gdt_page);
+INIT_PER_CPU(irq_stack_union);
+
+/*
+ * Build-time check on the image size:
+ */
+ASSERT((_end - _text <= KERNEL_IMAGE_SIZE),
+       "kernel image bigger than KERNEL_IMAGE_SIZE")
+
+#ifdef CONFIG_SMP
+ASSERT((per_cpu__irq_stack_union == 0),
+        "irq_stack_union is not at start of per-cpu area");
+#endif
+
+#endif /* CONFIG_X86_32 */
+
+#ifdef CONFIG_KEXEC
+#include <asm/kexec.h>
+
+ASSERT(kexec_control_code_size <= KEXEC_CONTROL_CODE_MAX_SIZE,
+       "kexec control code size is too big")
+#endif
+
diff --git a/arch/x86/kernel/vmlinux_32.lds.S b/arch/x86/kernel/vmlinux_32.lds.S
deleted file mode 100644 (file)
index 62ad500..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/* ld script to make i386 Linux kernel
- * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
- *
- * Don't define absolute symbols until and unless you know that symbol
- * value is should remain constant even if kernel image is relocated
- * at run time. Absolute symbols are not relocated. If symbol value should
- * change if kernel is relocated, make the symbol section relative and
- * put it inside the section definition.
- */
-
-#define LOAD_OFFSET __PAGE_OFFSET
-
-#include <asm-generic/vmlinux.lds.h>
-#include <asm/thread_info.h>
-#include <asm/page_types.h>
-#include <asm/cache.h>
-#include <asm/boot.h>
-
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
-OUTPUT_ARCH(i386)
-ENTRY(phys_startup_32)
-jiffies = jiffies_64;
-
-PHDRS {
-       text PT_LOAD FLAGS(5);  /* R_E */
-       data PT_LOAD FLAGS(7);  /* RWE */
-       note PT_NOTE FLAGS(0);  /* ___ */
-}
-SECTIONS
-{
-  . = LOAD_OFFSET + LOAD_PHYSICAL_ADDR;
-  phys_startup_32 = startup_32 - LOAD_OFFSET;
-
-  .text.head : AT(ADDR(.text.head) - LOAD_OFFSET) {
-       _text = .;                      /* Text and read-only data */
-       *(.text.head)
-  } :text = 0x9090
-
-  /* read-only */
-  .text : AT(ADDR(.text) - LOAD_OFFSET) {
-       . = ALIGN(PAGE_SIZE); /* not really needed, already page aligned */
-       *(.text.page_aligned)
-       TEXT_TEXT
-       SCHED_TEXT
-       LOCK_TEXT
-       KPROBES_TEXT
-       IRQENTRY_TEXT
-       *(.fixup)
-       *(.gnu.warning)
-       _etext = .;                     /* End of text section */
-  } :text = 0x9090
-
-  NOTES :text :note
-
-  . = ALIGN(16);               /* Exception table */
-  __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
-       __start___ex_table = .;
-        *(__ex_table)
-       __stop___ex_table = .;
-  } :text = 0x9090
-
-  RODATA
-
-  /* writeable */
-  . = ALIGN(PAGE_SIZE);
-  .data : AT(ADDR(.data) - LOAD_OFFSET) {      /* Data */
-       DATA_DATA
-       CONSTRUCTORS
-       } :data
-
-  . = ALIGN(PAGE_SIZE);
-  .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) {
-       __nosave_begin = .;
-       *(.data.nosave)
-       . = ALIGN(PAGE_SIZE);
-       __nosave_end = .;
-  }
-
-  . = ALIGN(PAGE_SIZE);
-  .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
-       *(.data.page_aligned)
-       *(.data.idt)
-  }
-
-  . = ALIGN(32);
-  .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
-       *(.data.cacheline_aligned)
-  }
-
-  /* rarely changed data like cpu maps */
-  . = ALIGN(32);
-  .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) {
-       *(.data.read_mostly)
-       _edata = .;             /* End of data section */
-  }
-
-  . = ALIGN(THREAD_SIZE);      /* init_task */
-  .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
-       *(.data.init_task)
-  }
-
-  /* might get freed after init */
-  . = ALIGN(PAGE_SIZE);
-  .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
-       __smp_locks = .;
-       *(.smp_locks)
-       __smp_locks_end = .;
-  }
-  /* will be freed after init
-   * Following ALIGN() is required to make sure no other data falls on the
-   * same page where __smp_alt_end is pointing as that page might be freed
-   * after boot. Always make sure that ALIGN() directive is present after
-   * the section which contains __smp_alt_end.
-   */
-  . = ALIGN(PAGE_SIZE);
-
-  /* will be freed after init */
-  . = ALIGN(PAGE_SIZE);                /* Init code and data */
-  .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
-       __init_begin = .;
-       _sinittext = .;
-       INIT_TEXT
-       _einittext = .;
-  }
-  .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {
-       INIT_DATA
-  }
-  . = ALIGN(16);
-  .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
-       __setup_start = .;
-       *(.init.setup)
-       __setup_end = .;
-   }
-  .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
-       __initcall_start = .;
-       INITCALLS
-       __initcall_end = .;
-  }
-  .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
-       __con_initcall_start = .;
-       *(.con_initcall.init)
-       __con_initcall_end = .;
-  }
-  .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
-       __x86_cpu_dev_start = .;
-       *(.x86_cpu_dev.init)
-       __x86_cpu_dev_end = .;
-  }
-  SECURITY_INIT
-  . = ALIGN(4);
-  .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
-       __alt_instructions = .;
-       *(.altinstructions)
-       __alt_instructions_end = .;
-  }
-  .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
-       *(.altinstr_replacement)
-  }
-  . = ALIGN(4);
-  .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) {
-       __parainstructions = .;
-       *(.parainstructions)
-       __parainstructions_end = .;
-  }
-  /* .exit.text is discard at runtime, not link time, to deal with references
-     from .altinstructions and .eh_frame */
-  .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) {
-       EXIT_TEXT
-  }
-  .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) {
-       EXIT_DATA
-  }
-#if defined(CONFIG_BLK_DEV_INITRD)
-  . = ALIGN(PAGE_SIZE);
-  .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
-       __initramfs_start = .;
-       *(.init.ramfs)
-       __initramfs_end = .;
-  }
-#endif
-  PERCPU(PAGE_SIZE)
-  . = ALIGN(PAGE_SIZE);
-  /* freed after init ends here */
-
-  .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
-       __init_end = .;
-       __bss_start = .;                /* BSS */
-       *(.bss.page_aligned)
-       *(.bss)
-       . = ALIGN(4);
-       __bss_stop = .;
-  }
-
-  .brk : AT(ADDR(.brk) - LOAD_OFFSET) {
-       . = ALIGN(PAGE_SIZE);
-       __brk_base = . ;
-       . += 64 * 1024 ;        /* 64k alignment slop space */
-       *(.brk_reservation)     /* areas brk users have reserved */
-       __brk_limit = . ;
-  }
-
-  .end : AT(ADDR(.end) - LOAD_OFFSET) {
-       _end = . ;
-  }
-
-  /* Sections to be discarded */
-  /DISCARD/ : {
-       *(.exitcall.exit)
-       *(.discard)
-       }
-
-  STABS_DEBUG
-
-  DWARF_DEBUG
-}
-
-/*
- * Build-time check on the image size:
- */
-ASSERT((_end - LOAD_OFFSET <= KERNEL_IMAGE_SIZE),
-       "kernel image bigger than KERNEL_IMAGE_SIZE")
-
-#ifdef CONFIG_KEXEC
-/* Link time checks */
-#include <asm/kexec.h>
-
-ASSERT(kexec_control_code_size <= KEXEC_CONTROL_CODE_MAX_SIZE,
-       "kexec control code size is too big")
-#endif
diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S
deleted file mode 100644 (file)
index c874250..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-/* ld script to make x86-64 Linux kernel
- * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
- */
-
-#define LOAD_OFFSET __START_KERNEL_map
-
-#include <asm-generic/vmlinux.lds.h>
-#include <asm/asm-offsets.h>
-#include <asm/page_types.h>
-
-#undef i386    /* in case the preprocessor is a 32bit one */
-
-OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
-OUTPUT_ARCH(i386:x86-64)
-ENTRY(phys_startup_64)
-jiffies_64 = jiffies;
-PHDRS {
-       text PT_LOAD FLAGS(5);  /* R_E */
-       data PT_LOAD FLAGS(7);  /* RWE */
-       user PT_LOAD FLAGS(7);  /* RWE */
-       data.init PT_LOAD FLAGS(7);     /* RWE */
-#ifdef CONFIG_SMP
-       percpu PT_LOAD FLAGS(7);        /* RWE */
-#endif
-       data.init2 PT_LOAD FLAGS(7);    /* RWE */
-       note PT_NOTE FLAGS(0);  /* ___ */
-}
-SECTIONS
-{
-  . = __START_KERNEL;
-  phys_startup_64 = startup_64 - LOAD_OFFSET;
-  .text :  AT(ADDR(.text) - LOAD_OFFSET) {
-       _text = .;                      /* Text and read-only data */
-       /* First the code that has to be first for bootstrapping */
-       *(.text.head)
-       _stext = .;
-       /* Then the rest */
-       TEXT_TEXT
-       SCHED_TEXT
-       LOCK_TEXT
-       KPROBES_TEXT
-       IRQENTRY_TEXT
-       *(.fixup)
-       *(.gnu.warning)
-       _etext = .;             /* End of text section */
-  } :text = 0x9090
-
-  NOTES :text :note
-
-  . = ALIGN(16);               /* Exception table */
-  __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
-       __start___ex_table = .;
-        *(__ex_table)
-       __stop___ex_table = .;
-  } :text = 0x9090
-
-  RODATA
-
-  . = ALIGN(PAGE_SIZE);                /* Align data segment to page size boundary */
-                               /* Data */
-  .data : AT(ADDR(.data) - LOAD_OFFSET) {
-       DATA_DATA
-       CONSTRUCTORS
-       _edata = .;                     /* End of data section */
-       } :data
-
-
-  .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
-       . = ALIGN(PAGE_SIZE);
-       . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
-       *(.data.cacheline_aligned)
-  }
-  . = ALIGN(CONFIG_X86_INTERNODE_CACHE_BYTES);
-  .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) {
-       *(.data.read_mostly)
-  }
-
-#define VSYSCALL_ADDR (-10*1024*1024)
-#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095))
-#define VSYSCALL_VIRT_ADDR ((ADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095))
-
-#define VLOAD_OFFSET (VSYSCALL_ADDR - VSYSCALL_PHYS_ADDR)
-#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET)
-
-#define VVIRT_OFFSET (VSYSCALL_ADDR - VSYSCALL_VIRT_ADDR)
-#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET)
-
-  . = VSYSCALL_ADDR;
-  .vsyscall_0 :         AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) } :user
-  __vsyscall_0 = VSYSCALL_VIRT_ADDR;
-
-  . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
-  .vsyscall_fn : AT(VLOAD(.vsyscall_fn)) { *(.vsyscall_fn) }
-  . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
-  .vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data))
-               { *(.vsyscall_gtod_data) }
-  vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data);
-  .vsyscall_clock : AT(VLOAD(.vsyscall_clock))
-               { *(.vsyscall_clock) }
-  vsyscall_clock = VVIRT(.vsyscall_clock);
-
-
-  .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1))
-               { *(.vsyscall_1) }
-  .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2))
-               { *(.vsyscall_2) }
-
-  .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) }
-  vgetcpu_mode = VVIRT(.vgetcpu_mode);
-
-  . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
-  .jiffies : AT(VLOAD(.jiffies)) { *(.jiffies) }
-  jiffies = VVIRT(.jiffies);
-
-  .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3))
-               { *(.vsyscall_3) }
-
-  . = VSYSCALL_VIRT_ADDR + PAGE_SIZE;
-
-#undef VSYSCALL_ADDR
-#undef VSYSCALL_PHYS_ADDR
-#undef VSYSCALL_VIRT_ADDR
-#undef VLOAD_OFFSET
-#undef VLOAD
-#undef VVIRT_OFFSET
-#undef VVIRT
-
-  .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
-       . = ALIGN(THREAD_SIZE); /* init_task */
-       *(.data.init_task)
-  }:data.init
-
-  .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
-       . = ALIGN(PAGE_SIZE);
-       *(.data.page_aligned)
-  }
-
-  .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
-       /* might get freed after init */
-       . = ALIGN(PAGE_SIZE);
-       __smp_alt_begin = .;
-       __smp_locks = .;
-       *(.smp_locks)
-       __smp_locks_end = .;
-       . = ALIGN(PAGE_SIZE);
-       __smp_alt_end = .;
-  }
-
-  . = ALIGN(PAGE_SIZE);                /* Init code and data */
-  __init_begin = .;    /* paired with __init_end */
-  .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
-       _sinittext = .;
-       INIT_TEXT
-       _einittext = .;
-  }
-  .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {
-       __initdata_begin = .;
-       INIT_DATA
-       __initdata_end = .;
-   }
-
-  .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
-       . = ALIGN(16);
-       __setup_start = .;
-       *(.init.setup)
-       __setup_end = .;
-  }
-  .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
-       __initcall_start = .;
-       INITCALLS
-       __initcall_end = .;
-  }
-  .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
-       __con_initcall_start = .;
-       *(.con_initcall.init)
-       __con_initcall_end = .;
-  }
-  .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
-       __x86_cpu_dev_start = .;
-       *(.x86_cpu_dev.init)
-       __x86_cpu_dev_end = .;
-  }
-  SECURITY_INIT
-
-  . = ALIGN(8);
-  .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) {
-       __parainstructions = .;
-       *(.parainstructions)
-       __parainstructions_end = .;
-  }
-
-  .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
-       . = ALIGN(8);
-       __alt_instructions = .;
-       *(.altinstructions)
-       __alt_instructions_end = .;
-  }
-  .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
-       *(.altinstr_replacement)
-  }
-  /* .exit.text is discard at runtime, not link time, to deal with references
-     from .altinstructions and .eh_frame */
-  .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) {
-       EXIT_TEXT
-  }
-  .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) {
-       EXIT_DATA
-  }
-
-#ifdef CONFIG_BLK_DEV_INITRD
-  . = ALIGN(PAGE_SIZE);
-  .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
-       __initramfs_start = .;
-       *(.init.ramfs)
-       __initramfs_end = .;
-  }
-#endif
-
-#ifdef CONFIG_SMP
-  /*
-   * percpu offsets are zero-based on SMP.  PERCPU_VADDR() changes the
-   * output PHDR, so the next output section - __data_nosave - should
-   * start another section data.init2.  Also, pda should be at the head of
-   * percpu area.  Preallocate it and define the percpu offset symbol
-   * so that it can be accessed as a percpu variable.
-   */
-  . = ALIGN(PAGE_SIZE);
-  PERCPU_VADDR(0, :percpu)
-#else
-  PERCPU(PAGE_SIZE)
-#endif
-
-  . = ALIGN(PAGE_SIZE);
-  __init_end = .;
-
-  .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) {
-       . = ALIGN(PAGE_SIZE);
-       __nosave_begin = .;
-       *(.data.nosave)
-       . = ALIGN(PAGE_SIZE);
-       __nosave_end = .;
-  } :data.init2 /* use another section data.init2, see PERCPU_VADDR() above */
-
-  .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
-       . = ALIGN(PAGE_SIZE);
-       __bss_start = .;                /* BSS */
-       *(.bss.page_aligned)
-       *(.bss)
-       __bss_stop = .;
-  }
-
-  .brk : AT(ADDR(.brk) - LOAD_OFFSET) {
-       . = ALIGN(PAGE_SIZE);
-       __brk_base = . ;
-       . += 64 * 1024 ;        /* 64k alignment slop space */
-       *(.brk_reservation)     /* areas brk users have reserved */
-       __brk_limit = . ;
-  }
-
-  _end = . ;
-
-  /* Sections to be discarded */
-  /DISCARD/ : {
-       *(.exitcall.exit)
-       *(.eh_frame)
-       *(.discard)
-       }
-
-  STABS_DEBUG
-
-  DWARF_DEBUG
-}
-
- /*
-  * Per-cpu symbols which need to be offset from __per_cpu_load
-  * for the boot processor.
-  */
-#define INIT_PER_CPU(x) init_per_cpu__##x = per_cpu__##x + __per_cpu_load
-INIT_PER_CPU(gdt_page);
-INIT_PER_CPU(irq_stack_union);
-
-/*
- * Build-time check on the image size:
- */
-ASSERT((_end - _text <= KERNEL_IMAGE_SIZE),
-       "kernel image bigger than KERNEL_IMAGE_SIZE")
-
-#ifdef CONFIG_SMP
-ASSERT((per_cpu__irq_stack_union == 0),
-        "irq_stack_union is not at start of per-cpu area");
-#endif
-
-#ifdef CONFIG_KEXEC
-#include <asm/kexec.h>
-
-ASSERT(kexec_control_code_size <= KEXEC_CONTROL_CODE_MAX_SIZE,
-       "kexec control code size is too big")
-#endif
index 44153afc9067558cef387ba3237ffcf439ca3800..25ee06a80aad3cd116292227826f9a32fa4b3f7a 100644 (file)
@@ -132,15 +132,7 @@ static __always_inline void do_vgettimeofday(struct timeval * tv)
                        return;
                }
 
-               /*
-                * Surround the RDTSC by barriers, to make sure it's not
-                * speculated to outside the seqlock critical section and
-                * does not cause time warps:
-                */
-               rdtsc_barrier();
                now = vread();
-               rdtsc_barrier();
-
                base = __vsyscall_gtod_data.clock.cycle_last;
                mask = __vsyscall_gtod_data.clock.mask;
                mult = __vsyscall_gtod_data.clock.mult;
index a58504ea78ccb90d766e8efbcc5563ef0b0d1303..8600a09e0c6c5cca00331605a92045d34268133b 100644 (file)
@@ -50,6 +50,9 @@ config KVM_INTEL
          Provides support for KVM on Intel processors equipped with the VT
          extensions.
 
+         To compile this as a module, choose M here: the module
+         will be called kvm-intel.
+
 config KVM_AMD
        tristate "KVM for AMD processors support"
        depends on KVM
@@ -57,6 +60,9 @@ config KVM_AMD
          Provides support for KVM on AMD processors equipped with the AMD-V
          (SVM) extensions.
 
+         To compile this as a module, choose M here: the module
+         will be called kvm-amd.
+
 config KVM_TRACE
        bool "KVM trace support"
        depends on KVM && SYSFS
index d3ec292f00f248e9d41e67813775f1867de8b0a5..b43c4efafe80133cab8ab26a4bbabc9e5fac263a 100644 (file)
@@ -14,7 +14,7 @@ endif
 EXTRA_CFLAGS += -Ivirt/kvm -Iarch/x86/kvm
 
 kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o \
-       i8254.o
+       i8254.o timer.o
 obj-$(CONFIG_KVM) += kvm.o
 kvm-intel-objs = vmx.o
 obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
index c13bb92d3157708a52e211b1992a71f45554ffbb..4d6f0d293ee29bb303dbe5e4b81b4cb3c9e2b6e2 100644 (file)
@@ -98,6 +98,37 @@ static int pit_get_gate(struct kvm *kvm, int channel)
        return kvm->arch.vpit->pit_state.channels[channel].gate;
 }
 
+static s64 __kpit_elapsed(struct kvm *kvm)
+{
+       s64 elapsed;
+       ktime_t remaining;
+       struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state;
+
+       /*
+        * The Counter does not stop when it reaches zero. In
+        * Modes 0, 1, 4, and 5 the Counter ``wraps around'' to
+        * the highest count, either FFFF hex for binary counting
+        * or 9999 for BCD counting, and continues counting.
+        * Modes 2 and 3 are periodic; the Counter reloads
+        * itself with the initial count and continues counting
+        * from there.
+        */
+       remaining = hrtimer_expires_remaining(&ps->pit_timer.timer);
+       elapsed = ps->pit_timer.period - ktime_to_ns(remaining);
+       elapsed = mod_64(elapsed, ps->pit_timer.period);
+
+       return elapsed;
+}
+
+static s64 kpit_elapsed(struct kvm *kvm, struct kvm_kpit_channel_state *c,
+                       int channel)
+{
+       if (channel == 0)
+               return __kpit_elapsed(kvm);
+
+       return ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time));
+}
+
 static int pit_get_count(struct kvm *kvm, int channel)
 {
        struct kvm_kpit_channel_state *c =
@@ -107,7 +138,7 @@ static int pit_get_count(struct kvm *kvm, int channel)
 
        WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock));
 
-       t = ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time));
+       t = kpit_elapsed(kvm, c, channel);
        d = muldiv64(t, KVM_PIT_FREQ, NSEC_PER_SEC);
 
        switch (c->mode) {
@@ -137,7 +168,7 @@ static int pit_get_out(struct kvm *kvm, int channel)
 
        WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock));
 
-       t = ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time));
+       t = kpit_elapsed(kvm, c, channel);
        d = muldiv64(t, KVM_PIT_FREQ, NSEC_PER_SEC);
 
        switch (c->mode) {
@@ -193,28 +224,6 @@ static void pit_latch_status(struct kvm *kvm, int channel)
        }
 }
 
-static int __pit_timer_fn(struct kvm_kpit_state *ps)
-{
-       struct kvm_vcpu *vcpu0 = ps->pit->kvm->vcpus[0];
-       struct kvm_kpit_timer *pt = &ps->pit_timer;
-
-       if (!atomic_inc_and_test(&pt->pending))
-               set_bit(KVM_REQ_PENDING_TIMER, &vcpu0->requests);
-
-       if (!pt->reinject)
-               atomic_set(&pt->pending, 1);
-
-       if (vcpu0 && waitqueue_active(&vcpu0->wq))
-               wake_up_interruptible(&vcpu0->wq);
-
-       hrtimer_add_expires_ns(&pt->timer, pt->period);
-       pt->scheduled = hrtimer_get_expires_ns(&pt->timer);
-       if (pt->period)
-               ps->channels[0].count_load_time = ktime_get();
-
-       return (pt->period == 0 ? 0 : 1);
-}
-
 int pit_has_pending_timer(struct kvm_vcpu *vcpu)
 {
        struct kvm_pit *pit = vcpu->kvm->arch.vpit;
@@ -235,21 +244,6 @@ static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian)
        spin_unlock(&ps->inject_lock);
 }
 
-static enum hrtimer_restart pit_timer_fn(struct hrtimer *data)
-{
-       struct kvm_kpit_state *ps;
-       int restart_timer = 0;
-
-       ps = container_of(data, struct kvm_kpit_state, pit_timer.timer);
-
-       restart_timer = __pit_timer_fn(ps);
-
-       if (restart_timer)
-               return HRTIMER_RESTART;
-       else
-               return HRTIMER_NORESTART;
-}
-
 void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu)
 {
        struct kvm_pit *pit = vcpu->kvm->arch.vpit;
@@ -263,15 +257,26 @@ void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu)
                hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
 }
 
-static void destroy_pit_timer(struct kvm_kpit_timer *pt)
+static void destroy_pit_timer(struct kvm_timer *pt)
 {
        pr_debug("pit: execute del timer!\n");
        hrtimer_cancel(&pt->timer);
 }
 
+static bool kpit_is_periodic(struct kvm_timer *ktimer)
+{
+       struct kvm_kpit_state *ps = container_of(ktimer, struct kvm_kpit_state,
+                                                pit_timer);
+       return ps->is_periodic;
+}
+
+static struct kvm_timer_ops kpit_ops = {
+       .is_periodic = kpit_is_periodic,
+};
+
 static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period)
 {
-       struct kvm_kpit_timer *pt = &ps->pit_timer;
+       struct kvm_timer *pt = &ps->pit_timer;
        s64 interval;
 
        interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ);
@@ -280,8 +285,14 @@ static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period)
 
        /* TODO The new value only affected after the retriggered */
        hrtimer_cancel(&pt->timer);
-       pt->period = (is_period == 0) ? 0 : interval;
-       pt->timer.function = pit_timer_fn;
+       pt->period = interval;
+       ps->is_periodic = is_period;
+
+       pt->timer.function = kvm_timer_fn;
+       pt->t_ops = &kpit_ops;
+       pt->kvm = ps->pit->kvm;
+       pt->vcpu_id = 0;
+
        atomic_set(&pt->pending, 0);
        ps->irq_ack = 1;
 
@@ -298,23 +309,23 @@ static void pit_load_count(struct kvm *kvm, int channel, u32 val)
        pr_debug("pit: load_count val is %d, channel is %d\n", val, channel);
 
        /*
-        * Though spec said the state of 8254 is undefined after power-up,
-        * seems some tricky OS like Windows XP depends on IRQ0 interrupt
-        * when booting up.
-        * So here setting initialize rate for it, and not a specific number
+        * The largest possible initial count is 0; this is equivalent
+        * to 216 for binary counting and 104 for BCD counting.
         */
        if (val == 0)
                val = 0x10000;
 
-       ps->channels[channel].count_load_time = ktime_get();
        ps->channels[channel].count = val;
 
-       if (channel != 0)
+       if (channel != 0) {
+               ps->channels[channel].count_load_time = ktime_get();
                return;
+       }
 
        /* Two types of timer
         * mode 1 is one shot, mode 2 is period, otherwise del timer */
        switch (ps->channels[0].mode) {
+       case 0:
        case 1:
         /* FIXME: enhance mode 4 precision */
        case 4:
index 6acbe4b505d5faad09d6b7d69e2cc64e870965cc..bbd863ff60b701591eee82be07993412af2adeb1 100644 (file)
@@ -3,15 +3,6 @@
 
 #include "iodev.h"
 
-struct kvm_kpit_timer {
-       struct hrtimer timer;
-       int irq;
-       s64 period; /* unit: ns */
-       s64 scheduled;
-       atomic_t pending;
-       bool reinject;
-};
-
 struct kvm_kpit_channel_state {
        u32 count; /* can be 65536 */
        u16 latched_count;
@@ -30,7 +21,8 @@ struct kvm_kpit_channel_state {
 
 struct kvm_kpit_state {
        struct kvm_kpit_channel_state channels[3];
-       struct kvm_kpit_timer pit_timer;
+       struct kvm_timer pit_timer;
+       bool is_periodic;
        u32    speaker_data_on;
        struct mutex lock;
        struct kvm_pit *pit;
index cf17ed52f6fbbe33563668604df0fa814f3cf493..96dfbb6ad2a9d2b1db365ef0c007f9d7056d9dda 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "irq.h"
 #include "i8254.h"
+#include "x86.h"
 
 /*
  * check if there are pending timer events
@@ -48,6 +49,9 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
 {
        struct kvm_pic *s;
 
+       if (!irqchip_in_kernel(v->kvm))
+               return v->arch.interrupt.pending;
+
        if (kvm_apic_has_interrupt(v) == -1) {  /* LAPIC */
                if (kvm_apic_accept_pic_intr(v)) {
                        s = pic_irqchip(v->kvm);        /* PIC */
@@ -67,6 +71,9 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
        struct kvm_pic *s;
        int vector;
 
+       if (!irqchip_in_kernel(v->kvm))
+               return v->arch.interrupt.nr;
+
        vector = kvm_get_apic_interrupt(v);     /* APIC */
        if (vector == -1) {
                if (kvm_apic_accept_pic_intr(v)) {
diff --git a/arch/x86/kvm/kvm_timer.h b/arch/x86/kvm/kvm_timer.h
new file mode 100644 (file)
index 0000000..26bd6ba
--- /dev/null
@@ -0,0 +1,18 @@
+
+struct kvm_timer {
+       struct hrtimer timer;
+       s64 period;                             /* unit: ns */
+       atomic_t pending;                       /* accumulated triggered timers */
+       bool reinject;
+       struct kvm_timer_ops *t_ops;
+       struct kvm *kvm;
+       int vcpu_id;
+};
+
+struct kvm_timer_ops {
+        bool (*is_periodic)(struct kvm_timer *);
+};
+
+
+enum hrtimer_restart kvm_timer_fn(struct hrtimer *data);
+
index f0b67f2cdd695a71c636ddfbe45b9ec9248b0748..ae99d83f81a34384d72859a69233ace1dd8fa433 100644 (file)
@@ -196,20 +196,15 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr);
 
-int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig)
+static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
+                            int vector, int level, int trig_mode);
+
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
 
-       if (!apic_test_and_set_irr(vec, apic)) {
-               /* a new pending irq is set in IRR */
-               if (trig)
-                       apic_set_vector(vec, apic->regs + APIC_TMR);
-               else
-                       apic_clear_vector(vec, apic->regs + APIC_TMR);
-               kvm_vcpu_kick(apic->vcpu);
-               return 1;
-       }
-       return 0;
+       return __apic_accept_irq(apic, irq->delivery_mode, irq->vector,
+                       irq->level, irq->trig_mode);
 }
 
 static inline int apic_find_highest_isr(struct kvm_lapic *apic)
@@ -250,7 +245,7 @@ static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr)
 
 int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest)
 {
-       return kvm_apic_id(apic) == dest;
+       return dest == 0xff || kvm_apic_id(apic) == dest;
 }
 
 int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
@@ -279,37 +274,34 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
        return result;
 }
 
-static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
+int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
                           int short_hand, int dest, int dest_mode)
 {
        int result = 0;
        struct kvm_lapic *target = vcpu->arch.apic;
 
        apic_debug("target %p, source %p, dest 0x%x, "
-                  "dest_mode 0x%x, short_hand 0x%x",
+                  "dest_mode 0x%x, short_hand 0x%x\n",
                   target, source, dest, dest_mode, short_hand);
 
        ASSERT(!target);
        switch (short_hand) {
        case APIC_DEST_NOSHORT:
-               if (dest_mode == 0) {
+               if (dest_mode == 0)
                        /* Physical mode. */
-                       if ((dest == 0xFF) || (dest == kvm_apic_id(target)))
-                               result = 1;
-               } else
+                       result = kvm_apic_match_physical_addr(target, dest);
+               else
                        /* Logical mode. */
                        result = kvm_apic_match_logical_addr(target, dest);
                break;
        case APIC_DEST_SELF:
-               if (target == source)
-                       result = 1;
+               result = (target == source);
                break;
        case APIC_DEST_ALLINC:
                result = 1;
                break;
        case APIC_DEST_ALLBUT:
-               if (target != source)
-                       result = 1;
+               result = (target != source);
                break;
        default:
                printk(KERN_WARNING "Bad dest shorthand value %x\n",
@@ -327,20 +319,22 @@ static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
 static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                             int vector, int level, int trig_mode)
 {
-       int orig_irr, result = 0;
+       int result = 0;
        struct kvm_vcpu *vcpu = apic->vcpu;
 
        switch (delivery_mode) {
-       case APIC_DM_FIXED:
        case APIC_DM_LOWEST:
+               vcpu->arch.apic_arb_prio++;
+       case APIC_DM_FIXED:
                /* FIXME add logic for vcpu on reset */
                if (unlikely(!apic_enabled(apic)))
                        break;
 
-               orig_irr = apic_test_and_set_irr(vector, apic);
-               if (orig_irr && trig_mode) {
-                       apic_debug("level trig mode repeatedly for vector %d",
-                                  vector);
+               result = !apic_test_and_set_irr(vector, apic);
+               if (!result) {
+                       if (trig_mode)
+                               apic_debug("level trig mode repeatedly for "
+                                               "vector %d", vector);
                        break;
                }
 
@@ -349,10 +343,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                        apic_set_vector(vector, apic->regs + APIC_TMR);
                } else
                        apic_clear_vector(vector, apic->regs + APIC_TMR);
-
                kvm_vcpu_kick(vcpu);
-
-               result = (orig_irr == 0);
                break;
 
        case APIC_DM_REMRD:
@@ -364,12 +355,14 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                break;
 
        case APIC_DM_NMI:
+               result = 1;
                kvm_inject_nmi(vcpu);
                kvm_vcpu_kick(vcpu);
                break;
 
        case APIC_DM_INIT:
                if (level) {
+                       result = 1;
                        if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE)
                                printk(KERN_DEBUG
                                       "INIT on a runnable vcpu %d\n",
@@ -386,6 +379,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                apic_debug("SIPI to vcpu %d vector 0x%02x\n",
                           vcpu->vcpu_id, vector);
                if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) {
+                       result = 1;
                        vcpu->arch.sipi_vector = vector;
                        vcpu->arch.mp_state = KVM_MP_STATE_SIPI_RECEIVED;
                        kvm_vcpu_kick(vcpu);
@@ -408,43 +402,9 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
        return result;
 }
 
-static struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
-                                      unsigned long bitmap)
-{
-       int last;
-       int next;
-       struct kvm_lapic *apic = NULL;
-
-       last = kvm->arch.round_robin_prev_vcpu;
-       next = last;
-
-       do {
-               if (++next == KVM_MAX_VCPUS)
-                       next = 0;
-               if (kvm->vcpus[next] == NULL || !test_bit(next, &bitmap))
-                       continue;
-               apic = kvm->vcpus[next]->arch.apic;
-               if (apic && apic_enabled(apic))
-                       break;
-               apic = NULL;
-       } while (next != last);
-       kvm->arch.round_robin_prev_vcpu = next;
-
-       if (!apic)
-               printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n");
-
-       return apic;
-}
-
-struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
-               unsigned long bitmap)
+int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
 {
-       struct kvm_lapic *apic;
-
-       apic = kvm_apic_round_robin(kvm, vector, bitmap);
-       if (apic)
-               return apic->vcpu;
-       return NULL;
+       return vcpu1->arch.apic_arb_prio - vcpu2->arch.apic_arb_prio;
 }
 
 static void apic_set_eoi(struct kvm_lapic *apic)
@@ -472,47 +432,24 @@ static void apic_send_ipi(struct kvm_lapic *apic)
 {
        u32 icr_low = apic_get_reg(apic, APIC_ICR);
        u32 icr_high = apic_get_reg(apic, APIC_ICR2);
+       struct kvm_lapic_irq irq;
 
-       unsigned int dest = GET_APIC_DEST_FIELD(icr_high);
-       unsigned int short_hand = icr_low & APIC_SHORT_MASK;
-       unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG;
-       unsigned int level = icr_low & APIC_INT_ASSERT;
-       unsigned int dest_mode = icr_low & APIC_DEST_MASK;
-       unsigned int delivery_mode = icr_low & APIC_MODE_MASK;
-       unsigned int vector = icr_low & APIC_VECTOR_MASK;
-
-       struct kvm_vcpu *target;
-       struct kvm_vcpu *vcpu;
-       unsigned long lpr_map = 0;
-       int i;
+       irq.vector = icr_low & APIC_VECTOR_MASK;
+       irq.delivery_mode = icr_low & APIC_MODE_MASK;
+       irq.dest_mode = icr_low & APIC_DEST_MASK;
+       irq.level = icr_low & APIC_INT_ASSERT;
+       irq.trig_mode = icr_low & APIC_INT_LEVELTRIG;
+       irq.shorthand = icr_low & APIC_SHORT_MASK;
+       irq.dest_id = GET_APIC_DEST_FIELD(icr_high);
 
        apic_debug("icr_high 0x%x, icr_low 0x%x, "
                   "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
                   "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n",
-                  icr_high, icr_low, short_hand, dest,
-                  trig_mode, level, dest_mode, delivery_mode, vector);
-
-       for (i = 0; i < KVM_MAX_VCPUS; i++) {
-               vcpu = apic->vcpu->kvm->vcpus[i];
-               if (!vcpu)
-                       continue;
-
-               if (vcpu->arch.apic &&
-                   apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) {
-                       if (delivery_mode == APIC_DM_LOWEST)
-                               set_bit(vcpu->vcpu_id, &lpr_map);
-                       else
-                               __apic_accept_irq(vcpu->arch.apic, delivery_mode,
-                                                 vector, level, trig_mode);
-               }
-       }
+                  icr_high, icr_low, irq.shorthand, irq.dest_id,
+                  irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode,
+                  irq.vector);
 
-       if (delivery_mode == APIC_DM_LOWEST) {
-               target = kvm_get_lowest_prio_vcpu(vcpu->kvm, vector, lpr_map);
-               if (target != NULL)
-                       __apic_accept_irq(target->arch.apic, delivery_mode,
-                                         vector, level, trig_mode);
-       }
+       kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq);
 }
 
 static u32 apic_get_tmcct(struct kvm_lapic *apic)
@@ -527,12 +464,13 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
        if (apic_get_reg(apic, APIC_TMICT) == 0)
                return 0;
 
-       remaining = hrtimer_expires_remaining(&apic->timer.dev);
+       remaining = hrtimer_expires_remaining(&apic->lapic_timer.timer);
        if (ktime_to_ns(remaining) < 0)
                remaining = ktime_set(0, 0);
 
-       ns = mod_64(ktime_to_ns(remaining), apic->timer.period);
-       tmcct = div64_u64(ns, (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
+       ns = mod_64(ktime_to_ns(remaining), apic->lapic_timer.period);
+       tmcct = div64_u64(ns,
+                        (APIC_BUS_CYCLE_NS * apic->divide_count));
 
        return tmcct;
 }
@@ -619,25 +557,25 @@ static void update_divide_count(struct kvm_lapic *apic)
        tdcr = apic_get_reg(apic, APIC_TDCR);
        tmp1 = tdcr & 0xf;
        tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
-       apic->timer.divide_count = 0x1 << (tmp2 & 0x7);
+       apic->divide_count = 0x1 << (tmp2 & 0x7);
 
        apic_debug("timer divide count is 0x%x\n",
-                                  apic->timer.divide_count);
+                                  apic->divide_count);
 }
 
 static void start_apic_timer(struct kvm_lapic *apic)
 {
-       ktime_t now = apic->timer.dev.base->get_time();
+       ktime_t now = apic->lapic_timer.timer.base->get_time();
 
-       apic->timer.period = apic_get_reg(apic, APIC_TMICT) *
-                   APIC_BUS_CYCLE_NS * apic->timer.divide_count;
-       atomic_set(&apic->timer.pending, 0);
+       apic->lapic_timer.period = apic_get_reg(apic, APIC_TMICT) *
+                   APIC_BUS_CYCLE_NS * apic->divide_count;
+       atomic_set(&apic->lapic_timer.pending, 0);
 
-       if (!apic->timer.period)
+       if (!apic->lapic_timer.period)
                return;
 
-       hrtimer_start(&apic->timer.dev,
-                     ktime_add_ns(now, apic->timer.period),
+       hrtimer_start(&apic->lapic_timer.timer,
+                     ktime_add_ns(now, apic->lapic_timer.period),
                      HRTIMER_MODE_ABS);
 
        apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
@@ -646,9 +584,9 @@ static void start_apic_timer(struct kvm_lapic *apic)
                           "expire @ 0x%016" PRIx64 ".\n", __func__,
                           APIC_BUS_CYCLE_NS, ktime_to_ns(now),
                           apic_get_reg(apic, APIC_TMICT),
-                          apic->timer.period,
+                          apic->lapic_timer.period,
                           ktime_to_ns(ktime_add_ns(now,
-                                       apic->timer.period)));
+                                       apic->lapic_timer.period)));
 }
 
 static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val)
@@ -730,7 +668,7 @@ static void apic_mmio_write(struct kvm_io_device *this,
                                apic_set_reg(apic, APIC_LVTT + 0x10 * i,
                                             lvt_val | APIC_LVT_MASKED);
                        }
-                       atomic_set(&apic->timer.pending, 0);
+                       atomic_set(&apic->lapic_timer.pending, 0);
 
                }
                break;
@@ -762,7 +700,7 @@ static void apic_mmio_write(struct kvm_io_device *this,
                break;
 
        case APIC_TMICT:
-               hrtimer_cancel(&apic->timer.dev);
+               hrtimer_cancel(&apic->lapic_timer.timer);
                apic_set_reg(apic, APIC_TMICT, val);
                start_apic_timer(apic);
                return;
@@ -802,7 +740,7 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu)
        if (!vcpu->arch.apic)
                return;
 
-       hrtimer_cancel(&vcpu->arch.apic->timer.dev);
+       hrtimer_cancel(&vcpu->arch.apic->lapic_timer.timer);
 
        if (vcpu->arch.apic->regs_page)
                __free_page(vcpu->arch.apic->regs_page);
@@ -880,7 +818,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
        ASSERT(apic != NULL);
 
        /* Stop the timer in case it's a reset to an active apic */
-       hrtimer_cancel(&apic->timer.dev);
+       hrtimer_cancel(&apic->lapic_timer.timer);
 
        apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24);
        apic_set_reg(apic, APIC_LVR, APIC_VERSION);
@@ -905,11 +843,13 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
                apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
        }
        update_divide_count(apic);
-       atomic_set(&apic->timer.pending, 0);
+       atomic_set(&apic->lapic_timer.pending, 0);
        if (vcpu->vcpu_id == 0)
                vcpu->arch.apic_base |= MSR_IA32_APICBASE_BSP;
        apic_update_ppr(apic);
 
+       vcpu->arch.apic_arb_prio = 0;
+
        apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr="
                   "0x%016" PRIx64 ", base_address=0x%0lx.\n", __func__,
                   vcpu, kvm_apic_id(apic),
@@ -917,16 +857,14 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_lapic_reset);
 
-int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
+bool kvm_apic_present(struct kvm_vcpu *vcpu)
 {
-       struct kvm_lapic *apic = vcpu->arch.apic;
-       int ret = 0;
-
-       if (!apic)
-               return 0;
-       ret = apic_enabled(apic);
+       return vcpu->arch.apic && apic_hw_enabled(vcpu->arch.apic);
+}
 
-       return ret;
+int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
+{
+       return kvm_apic_present(vcpu) && apic_sw_enabled(vcpu->arch.apic);
 }
 EXPORT_SYMBOL_GPL(kvm_lapic_enabled);
 
@@ -936,22 +874,11 @@ EXPORT_SYMBOL_GPL(kvm_lapic_enabled);
  *----------------------------------------------------------------------
  */
 
-/* TODO: make sure __apic_timer_fn runs in current pCPU */
-static int __apic_timer_fn(struct kvm_lapic *apic)
+static bool lapic_is_periodic(struct kvm_timer *ktimer)
 {
-       int result = 0;
-       wait_queue_head_t *q = &apic->vcpu->wq;
-
-       if(!atomic_inc_and_test(&apic->timer.pending))
-               set_bit(KVM_REQ_PENDING_TIMER, &apic->vcpu->requests);
-       if (waitqueue_active(q))
-               wake_up_interruptible(q);
-
-       if (apic_lvtt_period(apic)) {
-               result = 1;
-               hrtimer_add_expires_ns(&apic->timer.dev, apic->timer.period);
-       }
-       return result;
+       struct kvm_lapic *apic = container_of(ktimer, struct kvm_lapic,
+                                             lapic_timer);
+       return apic_lvtt_period(apic);
 }
 
 int apic_has_pending_timer(struct kvm_vcpu *vcpu)
@@ -959,7 +886,7 @@ int apic_has_pending_timer(struct kvm_vcpu *vcpu)
        struct kvm_lapic *lapic = vcpu->arch.apic;
 
        if (lapic && apic_enabled(lapic) && apic_lvt_enabled(lapic, APIC_LVTT))
-               return atomic_read(&lapic->timer.pending);
+               return atomic_read(&lapic->lapic_timer.pending);
 
        return 0;
 }
@@ -986,20 +913,9 @@ void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu)
                kvm_apic_local_deliver(apic, APIC_LVT0);
 }
 
-static enum hrtimer_restart apic_timer_fn(struct hrtimer *data)
-{
-       struct kvm_lapic *apic;
-       int restart_timer = 0;
-
-       apic = container_of(data, struct kvm_lapic, timer.dev);
-
-       restart_timer = __apic_timer_fn(apic);
-
-       if (restart_timer)
-               return HRTIMER_RESTART;
-       else
-               return HRTIMER_NORESTART;
-}
+static struct kvm_timer_ops lapic_timer_ops = {
+       .is_periodic = lapic_is_periodic,
+};
 
 int kvm_create_lapic(struct kvm_vcpu *vcpu)
 {
@@ -1024,8 +940,13 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
        memset(apic->regs, 0, PAGE_SIZE);
        apic->vcpu = vcpu;
 
-       hrtimer_init(&apic->timer.dev, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
-       apic->timer.dev.function = apic_timer_fn;
+       hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC,
+                    HRTIMER_MODE_ABS);
+       apic->lapic_timer.timer.function = kvm_timer_fn;
+       apic->lapic_timer.t_ops = &lapic_timer_ops;
+       apic->lapic_timer.kvm = vcpu->kvm;
+       apic->lapic_timer.vcpu_id = vcpu->vcpu_id;
+
        apic->base_address = APIC_DEFAULT_PHYS_BASE;
        vcpu->arch.apic_base = APIC_DEFAULT_PHYS_BASE;
 
@@ -1078,9 +999,9 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
 
-       if (apic && atomic_read(&apic->timer.pending) > 0) {
+       if (apic && atomic_read(&apic->lapic_timer.pending) > 0) {
                if (kvm_apic_local_deliver(apic, APIC_LVTT))
-                       atomic_dec(&apic->timer.pending);
+                       atomic_dec(&apic->lapic_timer.pending);
        }
 }
 
@@ -1106,7 +1027,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
                             MSR_IA32_APICBASE_BASE;
        apic_set_reg(apic, APIC_LVR, APIC_VERSION);
        apic_update_ppr(apic);
-       hrtimer_cancel(&apic->timer.dev);
+       hrtimer_cancel(&apic->lapic_timer.timer);
        update_divide_count(apic);
        start_apic_timer(apic);
 }
@@ -1119,7 +1040,7 @@ void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
        if (!apic)
                return;
 
-       timer = &apic->timer.dev;
+       timer = &apic->lapic_timer.timer;
        if (hrtimer_cancel(timer))
                hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
 }
index 45ab6ee71209f586596447c0b1ad02feca125698..a587f8349c460d2e13d136e41002872ae278e0d5 100644 (file)
@@ -2,18 +2,15 @@
 #define __KVM_X86_LAPIC_H
 
 #include "iodev.h"
+#include "kvm_timer.h"
 
 #include <linux/kvm_host.h>
 
 struct kvm_lapic {
        unsigned long base_address;
        struct kvm_io_device dev;
-       struct {
-               atomic_t pending;
-               s64 period;     /* unit: ns */
-               u32 divide_count;
-               struct hrtimer dev;
-       } timer;
+       struct kvm_timer lapic_timer;
+       u32 divide_count;
        struct kvm_vcpu *vcpu;
        struct page *regs_page;
        void *regs;
@@ -34,12 +31,13 @@ u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
 
 int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
 int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
-int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig);
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq);
 
 u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
 void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data);
 void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu);
 int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
+bool kvm_apic_present(struct kvm_vcpu *vcpu);
 int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
 
 void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
index 32cf11e5728a2c1c444c407dfc287b8adf1c3c40..5c3d6e81a7dc61ec0b5ad6d952b77b96acb23b8f 100644 (file)
@@ -126,6 +126,7 @@ module_param(oos_shadow, bool, 0644);
 #define PFERR_PRESENT_MASK (1U << 0)
 #define PFERR_WRITE_MASK (1U << 1)
 #define PFERR_USER_MASK (1U << 2)
+#define PFERR_RSVD_MASK (1U << 3)
 #define PFERR_FETCH_MASK (1U << 4)
 
 #define PT_DIRECTORY_LEVEL 2
@@ -177,7 +178,11 @@ static u64 __read_mostly shadow_x_mask;    /* mutual exclusive with nx_mask */
 static u64 __read_mostly shadow_user_mask;
 static u64 __read_mostly shadow_accessed_mask;
 static u64 __read_mostly shadow_dirty_mask;
-static u64 __read_mostly shadow_mt_mask;
+
+static inline u64 rsvd_bits(int s, int e)
+{
+       return ((1ULL << (e - s + 1)) - 1) << s;
+}
 
 void kvm_mmu_set_nonpresent_ptes(u64 trap_pte, u64 notrap_pte)
 {
@@ -193,14 +198,13 @@ void kvm_mmu_set_base_ptes(u64 base_pte)
 EXPORT_SYMBOL_GPL(kvm_mmu_set_base_ptes);
 
 void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask,
-               u64 dirty_mask, u64 nx_mask, u64 x_mask, u64 mt_mask)
+               u64 dirty_mask, u64 nx_mask, u64 x_mask)
 {
        shadow_user_mask = user_mask;
        shadow_accessed_mask = accessed_mask;
        shadow_dirty_mask = dirty_mask;
        shadow_nx_mask = nx_mask;
        shadow_x_mask = x_mask;
-       shadow_mt_mask = mt_mask;
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_set_mask_ptes);
 
@@ -219,11 +223,6 @@ static int is_nx(struct kvm_vcpu *vcpu)
        return vcpu->arch.shadow_efer & EFER_NX;
 }
 
-static int is_present_pte(unsigned long pte)
-{
-       return pte & PT_PRESENT_MASK;
-}
-
 static int is_shadow_present_pte(u64 pte)
 {
        return pte != shadow_trap_nonpresent_pte
@@ -1074,18 +1073,10 @@ static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm *kvm, gfn_t gfn)
        return NULL;
 }
 
-static void kvm_unlink_unsync_global(struct kvm *kvm, struct kvm_mmu_page *sp)
-{
-       list_del(&sp->oos_link);
-       --kvm->stat.mmu_unsync_global;
-}
-
 static void kvm_unlink_unsync_page(struct kvm *kvm, struct kvm_mmu_page *sp)
 {
        WARN_ON(!sp->unsync);
        sp->unsync = 0;
-       if (sp->global)
-               kvm_unlink_unsync_global(kvm, sp);
        --kvm->stat.mmu_unsync;
 }
 
@@ -1248,7 +1239,6 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
        pgprintk("%s: adding gfn %lx role %x\n", __func__, gfn, role.word);
        sp->gfn = gfn;
        sp->role = role;
-       sp->global = 0;
        hlist_add_head(&sp->hash_link, bucket);
        if (!direct) {
                if (rmap_write_protect(vcpu->kvm, gfn))
@@ -1616,7 +1606,7 @@ static int get_mtrr_type(struct mtrr_state_type *mtrr_state,
        return mtrr_state->def_type;
 }
 
-static u8 get_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
+u8 kvm_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
 {
        u8 mtrr;
 
@@ -1626,6 +1616,7 @@ static u8 get_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
                mtrr = MTRR_TYPE_WRBACK;
        return mtrr;
 }
+EXPORT_SYMBOL_GPL(kvm_get_guest_memory_type);
 
 static int kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
 {
@@ -1646,11 +1637,7 @@ static int kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
        ++vcpu->kvm->stat.mmu_unsync;
        sp->unsync = 1;
 
-       if (sp->global) {
-               list_add(&sp->oos_link, &vcpu->kvm->arch.oos_global_pages);
-               ++vcpu->kvm->stat.mmu_unsync_global;
-       } else
-               kvm_mmu_mark_parents_unsync(vcpu, sp);
+       kvm_mmu_mark_parents_unsync(vcpu, sp);
 
        mmu_convert_notrap(sp);
        return 0;
@@ -1677,21 +1664,11 @@ static int mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
 static int set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
                    unsigned pte_access, int user_fault,
                    int write_fault, int dirty, int largepage,
-                   int global, gfn_t gfn, pfn_t pfn, bool speculative,
+                   gfn_t gfn, pfn_t pfn, bool speculative,
                    bool can_unsync)
 {
        u64 spte;
        int ret = 0;
-       u64 mt_mask = shadow_mt_mask;
-       struct kvm_mmu_page *sp = page_header(__pa(shadow_pte));
-
-       if (!global && sp->global) {
-               sp->global = 0;
-               if (sp->unsync) {
-                       kvm_unlink_unsync_global(vcpu->kvm, sp);
-                       kvm_mmu_mark_parents_unsync(vcpu, sp);
-               }
-       }
 
        /*
         * We don't set the accessed bit, since we sometimes want to see
@@ -1711,16 +1688,9 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
                spte |= shadow_user_mask;
        if (largepage)
                spte |= PT_PAGE_SIZE_MASK;
-       if (mt_mask) {
-               if (!kvm_is_mmio_pfn(pfn)) {
-                       mt_mask = get_memory_type(vcpu, gfn) <<
-                               kvm_x86_ops->get_mt_mask_shift();
-                       mt_mask |= VMX_EPT_IGMT_BIT;
-               } else
-                       mt_mask = MTRR_TYPE_UNCACHABLE <<
-                               kvm_x86_ops->get_mt_mask_shift();
-               spte |= mt_mask;
-       }
+       if (tdp_enabled)
+               spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn,
+                       kvm_is_mmio_pfn(pfn));
 
        spte |= (u64)pfn << PAGE_SHIFT;
 
@@ -1765,8 +1735,8 @@ set_pte:
 static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
                         unsigned pt_access, unsigned pte_access,
                         int user_fault, int write_fault, int dirty,
-                        int *ptwrite, int largepage, int global,
-                        gfn_t gfn, pfn_t pfn, bool speculative)
+                        int *ptwrite, int largepage, gfn_t gfn,
+                        pfn_t pfn, bool speculative)
 {
        int was_rmapped = 0;
        int was_writeble = is_writeble_pte(*shadow_pte);
@@ -1795,7 +1765,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
                        was_rmapped = 1;
        }
        if (set_spte(vcpu, shadow_pte, pte_access, user_fault, write_fault,
-                     dirty, largepage, global, gfn, pfn, speculative, true)) {
+                     dirty, largepage, gfn, pfn, speculative, true)) {
                if (write_fault)
                        *ptwrite = 1;
                kvm_x86_ops->tlb_flush(vcpu);
@@ -1843,7 +1813,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
                    || (largepage && iterator.level == PT_DIRECTORY_LEVEL)) {
                        mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, ACC_ALL,
                                     0, write, 1, &pt_write,
-                                    largepage, 0, gfn, pfn, false);
+                                    largepage, gfn, pfn, false);
                        ++vcpu->stat.pf_fixed;
                        break;
                }
@@ -1942,7 +1912,19 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
        vcpu->arch.mmu.root_hpa = INVALID_PAGE;
 }
 
-static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
+static int mmu_check_root(struct kvm_vcpu *vcpu, gfn_t root_gfn)
+{
+       int ret = 0;
+
+       if (!kvm_is_visible_gfn(vcpu->kvm, root_gfn)) {
+               set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
+               ret = 1;
+       }
+
+       return ret;
+}
+
+static int mmu_alloc_roots(struct kvm_vcpu *vcpu)
 {
        int i;
        gfn_t root_gfn;
@@ -1957,13 +1939,15 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
                ASSERT(!VALID_PAGE(root));
                if (tdp_enabled)
                        direct = 1;
+               if (mmu_check_root(vcpu, root_gfn))
+                       return 1;
                sp = kvm_mmu_get_page(vcpu, root_gfn, 0,
                                      PT64_ROOT_LEVEL, direct,
                                      ACC_ALL, NULL);
                root = __pa(sp->spt);
                ++sp->root_count;
                vcpu->arch.mmu.root_hpa = root;
-               return;
+               return 0;
        }
        direct = !is_paging(vcpu);
        if (tdp_enabled)
@@ -1980,6 +1964,8 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
                        root_gfn = vcpu->arch.pdptrs[i] >> PAGE_SHIFT;
                } else if (vcpu->arch.mmu.root_level == 0)
                        root_gfn = 0;
+               if (mmu_check_root(vcpu, root_gfn))
+                       return 1;
                sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
                                      PT32_ROOT_LEVEL, direct,
                                      ACC_ALL, NULL);
@@ -1988,6 +1974,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
                vcpu->arch.mmu.pae_root[i] = root | PT_PRESENT_MASK;
        }
        vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.pae_root);
+       return 0;
 }
 
 static void mmu_sync_roots(struct kvm_vcpu *vcpu)
@@ -2006,7 +1993,7 @@ static void mmu_sync_roots(struct kvm_vcpu *vcpu)
        for (i = 0; i < 4; ++i) {
                hpa_t root = vcpu->arch.mmu.pae_root[i];
 
-               if (root) {
+               if (root && VALID_PAGE(root)) {
                        root &= PT64_BASE_ADDR_MASK;
                        sp = page_header(root);
                        mmu_sync_children(vcpu, sp);
@@ -2014,15 +2001,6 @@ static void mmu_sync_roots(struct kvm_vcpu *vcpu)
        }
 }
 
-static void mmu_sync_global(struct kvm_vcpu *vcpu)
-{
-       struct kvm *kvm = vcpu->kvm;
-       struct kvm_mmu_page *sp, *n;
-
-       list_for_each_entry_safe(sp, n, &kvm->arch.oos_global_pages, oos_link)
-               kvm_sync_page(vcpu, sp);
-}
-
 void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu)
 {
        spin_lock(&vcpu->kvm->mmu_lock);
@@ -2030,13 +2008,6 @@ void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu)
        spin_unlock(&vcpu->kvm->mmu_lock);
 }
 
-void kvm_mmu_sync_global(struct kvm_vcpu *vcpu)
-{
-       spin_lock(&vcpu->kvm->mmu_lock);
-       mmu_sync_global(vcpu);
-       spin_unlock(&vcpu->kvm->mmu_lock);
-}
-
 static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr)
 {
        return vaddr;
@@ -2151,6 +2122,14 @@ static void paging_free(struct kvm_vcpu *vcpu)
        nonpaging_free(vcpu);
 }
 
+static bool is_rsvd_bits_set(struct kvm_vcpu *vcpu, u64 gpte, int level)
+{
+       int bit7;
+
+       bit7 = (gpte >> 7) & 1;
+       return (gpte & vcpu->arch.mmu.rsvd_bits_mask[bit7][level-1]) != 0;
+}
+
 #define PTTYPE 64
 #include "paging_tmpl.h"
 #undef PTTYPE
@@ -2159,6 +2138,59 @@ static void paging_free(struct kvm_vcpu *vcpu)
 #include "paging_tmpl.h"
 #undef PTTYPE
 
+static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level)
+{
+       struct kvm_mmu *context = &vcpu->arch.mmu;
+       int maxphyaddr = cpuid_maxphyaddr(vcpu);
+       u64 exb_bit_rsvd = 0;
+
+       if (!is_nx(vcpu))
+               exb_bit_rsvd = rsvd_bits(63, 63);
+       switch (level) {
+       case PT32_ROOT_LEVEL:
+               /* no rsvd bits for 2 level 4K page table entries */
+               context->rsvd_bits_mask[0][1] = 0;
+               context->rsvd_bits_mask[0][0] = 0;
+               if (is_cpuid_PSE36())
+                       /* 36bits PSE 4MB page */
+                       context->rsvd_bits_mask[1][1] = rsvd_bits(17, 21);
+               else
+                       /* 32 bits PSE 4MB page */
+                       context->rsvd_bits_mask[1][1] = rsvd_bits(13, 21);
+               context->rsvd_bits_mask[1][0] = ~0ull;
+               break;
+       case PT32E_ROOT_LEVEL:
+               context->rsvd_bits_mask[0][2] =
+                       rsvd_bits(maxphyaddr, 63) |
+                       rsvd_bits(7, 8) | rsvd_bits(1, 2);      /* PDPTE */
+               context->rsvd_bits_mask[0][1] = exb_bit_rsvd |
+                       rsvd_bits(maxphyaddr, 62);      /* PDE */
+               context->rsvd_bits_mask[0][0] = exb_bit_rsvd |
+                       rsvd_bits(maxphyaddr, 62);      /* PTE */
+               context->rsvd_bits_mask[1][1] = exb_bit_rsvd |
+                       rsvd_bits(maxphyaddr, 62) |
+                       rsvd_bits(13, 20);              /* large page */
+               context->rsvd_bits_mask[1][0] = ~0ull;
+               break;
+       case PT64_ROOT_LEVEL:
+               context->rsvd_bits_mask[0][3] = exb_bit_rsvd |
+                       rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8);
+               context->rsvd_bits_mask[0][2] = exb_bit_rsvd |
+                       rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8);
+               context->rsvd_bits_mask[0][1] = exb_bit_rsvd |
+                       rsvd_bits(maxphyaddr, 51);
+               context->rsvd_bits_mask[0][0] = exb_bit_rsvd |
+                       rsvd_bits(maxphyaddr, 51);
+               context->rsvd_bits_mask[1][3] = context->rsvd_bits_mask[0][3];
+               context->rsvd_bits_mask[1][2] = context->rsvd_bits_mask[0][2];
+               context->rsvd_bits_mask[1][1] = exb_bit_rsvd |
+                       rsvd_bits(maxphyaddr, 51) |
+                       rsvd_bits(13, 20);              /* large page */
+               context->rsvd_bits_mask[1][0] = ~0ull;
+               break;
+       }
+}
+
 static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level)
 {
        struct kvm_mmu *context = &vcpu->arch.mmu;
@@ -2179,6 +2211,7 @@ static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level)
 
 static int paging64_init_context(struct kvm_vcpu *vcpu)
 {
+       reset_rsvds_bits_mask(vcpu, PT64_ROOT_LEVEL);
        return paging64_init_context_common(vcpu, PT64_ROOT_LEVEL);
 }
 
@@ -2186,6 +2219,7 @@ static int paging32_init_context(struct kvm_vcpu *vcpu)
 {
        struct kvm_mmu *context = &vcpu->arch.mmu;
 
+       reset_rsvds_bits_mask(vcpu, PT32_ROOT_LEVEL);
        context->new_cr3 = paging_new_cr3;
        context->page_fault = paging32_page_fault;
        context->gva_to_gpa = paging32_gva_to_gpa;
@@ -2201,6 +2235,7 @@ static int paging32_init_context(struct kvm_vcpu *vcpu)
 
 static int paging32E_init_context(struct kvm_vcpu *vcpu)
 {
+       reset_rsvds_bits_mask(vcpu, PT32E_ROOT_LEVEL);
        return paging64_init_context_common(vcpu, PT32E_ROOT_LEVEL);
 }
 
@@ -2221,12 +2256,15 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
                context->gva_to_gpa = nonpaging_gva_to_gpa;
                context->root_level = 0;
        } else if (is_long_mode(vcpu)) {
+               reset_rsvds_bits_mask(vcpu, PT64_ROOT_LEVEL);
                context->gva_to_gpa = paging64_gva_to_gpa;
                context->root_level = PT64_ROOT_LEVEL;
        } else if (is_pae(vcpu)) {
+               reset_rsvds_bits_mask(vcpu, PT32E_ROOT_LEVEL);
                context->gva_to_gpa = paging64_gva_to_gpa;
                context->root_level = PT32E_ROOT_LEVEL;
        } else {
+               reset_rsvds_bits_mask(vcpu, PT32_ROOT_LEVEL);
                context->gva_to_gpa = paging32_gva_to_gpa;
                context->root_level = PT32_ROOT_LEVEL;
        }
@@ -2290,9 +2328,11 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu)
                goto out;
        spin_lock(&vcpu->kvm->mmu_lock);
        kvm_mmu_free_some_pages(vcpu);
-       mmu_alloc_roots(vcpu);
+       r = mmu_alloc_roots(vcpu);
        mmu_sync_roots(vcpu);
        spin_unlock(&vcpu->kvm->mmu_lock);
+       if (r)
+               goto out;
        kvm_x86_ops->set_cr3(vcpu, vcpu->arch.mmu.root_hpa);
        kvm_mmu_flush_tlb(vcpu);
 out:
@@ -2638,14 +2678,6 @@ EXPORT_SYMBOL_GPL(kvm_disable_tdp);
 
 static void free_mmu_pages(struct kvm_vcpu *vcpu)
 {
-       struct kvm_mmu_page *sp;
-
-       while (!list_empty(&vcpu->kvm->arch.active_mmu_pages)) {
-               sp = container_of(vcpu->kvm->arch.active_mmu_pages.next,
-                                 struct kvm_mmu_page, link);
-               kvm_mmu_zap_page(vcpu->kvm, sp);
-               cond_resched();
-       }
        free_page((unsigned long)vcpu->arch.mmu.pae_root);
 }
 
@@ -2710,7 +2742,6 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
 {
        struct kvm_mmu_page *sp;
 
-       spin_lock(&kvm->mmu_lock);
        list_for_each_entry(sp, &kvm->arch.active_mmu_pages, link) {
                int i;
                u64 *pt;
@@ -2725,7 +2756,6 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
                                pt[i] &= ~PT_WRITABLE_MASK;
        }
        kvm_flush_remote_tlbs(kvm);
-       spin_unlock(&kvm->mmu_lock);
 }
 
 void kvm_mmu_zap_all(struct kvm *kvm)
@@ -3007,11 +3037,13 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
                                       " in nonleaf level: levels %d gva %lx"
                                       " level %d pte %llx\n", audit_msg,
                                       vcpu->arch.mmu.root_level, va, level, ent);
-
-                       audit_mappings_page(vcpu, ent, va, level - 1);
+                       else
+                               audit_mappings_page(vcpu, ent, va, level - 1);
                } else {
                        gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, va);
-                       hpa_t hpa = (hpa_t)gpa_to_pfn(vcpu, gpa) << PAGE_SHIFT;
+                       gfn_t gfn = gpa >> PAGE_SHIFT;
+                       pfn_t pfn = gfn_to_pfn(vcpu->kvm, gfn);
+                       hpa_t hpa = (hpa_t)pfn << PAGE_SHIFT;
 
                        if (is_shadow_present_pte(ent)
                            && (ent & PT64_BASE_ADDR_MASK) != hpa)
index eaab2145f62b21d31558372d511b16d8f1bc57d4..3494a2fb136eec376707176bf38e006cb9c03053 100644 (file)
@@ -75,4 +75,9 @@ static inline int is_paging(struct kvm_vcpu *vcpu)
        return vcpu->arch.cr0 & X86_CR0_PG;
 }
 
+static inline int is_present_pte(unsigned long pte)
+{
+       return pte & PT_PRESENT_MASK;
+}
+
 #endif
index 6bd70206c56130ce95398c2c91a471ab471e9907..258e4591e1ca02246801fc380ae19472b2375b0a 100644 (file)
@@ -123,6 +123,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
        gfn_t table_gfn;
        unsigned index, pt_access, pte_access;
        gpa_t pte_gpa;
+       int rsvd_fault = 0;
 
        pgprintk("%s: addr %lx\n", __func__, addr);
 walk:
@@ -157,6 +158,10 @@ walk:
                if (!is_present_pte(pte))
                        goto not_present;
 
+               rsvd_fault = is_rsvd_bits_set(vcpu, pte, walker->level);
+               if (rsvd_fault)
+                       goto access_error;
+
                if (write_fault && !is_writeble_pte(pte))
                        if (user_fault || is_write_protection(vcpu))
                                goto access_error;
@@ -209,7 +214,6 @@ walk:
                if (ret)
                        goto walk;
                pte |= PT_DIRTY_MASK;
-               kvm_mmu_pte_write(vcpu, pte_gpa, (u8 *)&pte, sizeof(pte), 0);
                walker->ptes[walker->level - 1] = pte;
        }
 
@@ -233,6 +237,8 @@ err:
                walker->error_code |= PFERR_USER_MASK;
        if (fetch_fault)
                walker->error_code |= PFERR_FETCH_MASK;
+       if (rsvd_fault)
+               walker->error_code |= PFERR_RSVD_MASK;
        return 0;
 }
 
@@ -262,8 +268,7 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
        kvm_get_pfn(pfn);
        mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0,
                     gpte & PT_DIRTY_MASK, NULL, largepage,
-                    gpte & PT_GLOBAL_MASK, gpte_to_gfn(gpte),
-                    pfn, true);
+                    gpte_to_gfn(gpte), pfn, true);
 }
 
 /*
@@ -297,7 +302,6 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
                                     user_fault, write_fault,
                                     gw->ptes[gw->level-1] & PT_DIRTY_MASK,
                                     ptwrite, largepage,
-                                    gw->ptes[gw->level-1] & PT_GLOBAL_MASK,
                                     gw->gfn, pfn, false);
                        break;
                }
@@ -380,7 +384,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
                return r;
 
        /*
-        * Look up the shadow pte for the faulting address.
+        * Look up the guest pte for the faulting address.
         */
        r = FNAME(walk_addr)(&walker, vcpu, addr, write_fault, user_fault,
                             fetch_fault);
@@ -586,7 +590,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
                nr_present++;
                pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
                set_spte(vcpu, &sp->spt[i], pte_access, 0, 0,
-                        is_dirty_pte(gpte), 0, gpte & PT_GLOBAL_MASK, gfn,
+                        is_dirty_pte(gpte), 0, gfn,
                         spte_to_pfn(sp->spt[i]), true, false);
        }
 
index 1f8510c51d6e8abc2f315d9724e34708f49e2a6b..71510e07e69e062b5ce1626d6273cc2f03f39ccf 100644 (file)
@@ -19,6 +19,7 @@
 #include "irq.h"
 #include "mmu.h"
 #include "kvm_cache_regs.h"
+#include "x86.h"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -69,7 +70,6 @@ module_param(npt, int, S_IRUGO);
 static int nested = 0;
 module_param(nested, int, S_IRUGO);
 
-static void kvm_reput_irq(struct vcpu_svm *svm);
 static void svm_flush_tlb(struct kvm_vcpu *vcpu);
 
 static int nested_svm_exit_handled(struct vcpu_svm *svm, bool kvm_override);
@@ -132,24 +132,6 @@ static inline u32 svm_has(u32 feat)
        return svm_features & feat;
 }
 
-static inline u8 pop_irq(struct kvm_vcpu *vcpu)
-{
-       int word_index = __ffs(vcpu->arch.irq_summary);
-       int bit_index = __ffs(vcpu->arch.irq_pending[word_index]);
-       int irq = word_index * BITS_PER_LONG + bit_index;
-
-       clear_bit(bit_index, &vcpu->arch.irq_pending[word_index]);
-       if (!vcpu->arch.irq_pending[word_index])
-               clear_bit(word_index, &vcpu->arch.irq_summary);
-       return irq;
-}
-
-static inline void push_irq(struct kvm_vcpu *vcpu, u8 irq)
-{
-       set_bit(irq, vcpu->arch.irq_pending);
-       set_bit(irq / BITS_PER_LONG, &vcpu->arch.irq_summary);
-}
-
 static inline void clgi(void)
 {
        asm volatile (__ex(SVM_CLGI));
@@ -214,17 +196,31 @@ static void svm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
        svm->vmcb->control.event_inj_err = error_code;
 }
 
-static bool svm_exception_injected(struct kvm_vcpu *vcpu)
+static int is_external_interrupt(u32 info)
+{
+       info &= SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
+       return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR);
+}
+
+static u32 svm_get_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
+       u32 ret = 0;
 
-       return !(svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID);
+       if (svm->vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK)
+               ret |= X86_SHADOW_INT_STI | X86_SHADOW_INT_MOV_SS;
+       return ret & mask;
 }
 
-static int is_external_interrupt(u32 info)
+static void svm_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
 {
-       info &= SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
-       return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR);
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       if (mask == 0)
+               svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
+       else
+               svm->vmcb->control.int_state |= SVM_INTERRUPT_SHADOW_MASK;
+
 }
 
 static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
@@ -232,7 +228,9 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
        struct vcpu_svm *svm = to_svm(vcpu);
 
        if (!svm->next_rip) {
-               printk(KERN_DEBUG "%s: NOP\n", __func__);
+               if (emulate_instruction(vcpu, vcpu->run, 0, 0, EMULTYPE_SKIP) !=
+                               EMULATE_DONE)
+                       printk(KERN_DEBUG "%s: NOP\n", __func__);
                return;
        }
        if (svm->next_rip - kvm_rip_read(vcpu) > MAX_INST_SIZE)
@@ -240,9 +238,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
                       __func__, kvm_rip_read(vcpu), svm->next_rip);
 
        kvm_rip_write(vcpu, svm->next_rip);
-       svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
-
-       vcpu->arch.interrupt_window_open = (svm->vcpu.arch.hflags & HF_GIF_MASK);
+       svm_set_interrupt_shadow(vcpu, 0);
 }
 
 static int has_svm(void)
@@ -830,6 +826,15 @@ static void svm_get_segment(struct kvm_vcpu *vcpu,
                if (!var->unusable)
                        var->type |= 0x1;
                break;
+       case VCPU_SREG_SS:
+               /* On AMD CPUs sometimes the DB bit in the segment
+                * descriptor is left as 1, although the whole segment has
+                * been made unusable. Clear it here to pass an Intel VMX
+                * entry check when cross vendor migrating.
+                */
+               if (var->unusable)
+                       var->db = 0;
+               break;
        }
 }
 
@@ -960,15 +965,16 @@ static void svm_set_segment(struct kvm_vcpu *vcpu,
 
 }
 
-static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
+static void update_db_intercept(struct kvm_vcpu *vcpu)
 {
-       int old_debug = vcpu->guest_debug;
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       vcpu->guest_debug = dbg->control;
-
        svm->vmcb->control.intercept_exceptions &=
                ~((1 << DB_VECTOR) | (1 << BP_VECTOR));
+
+       if (vcpu->arch.singlestep)
+               svm->vmcb->control.intercept_exceptions |= (1 << DB_VECTOR);
+
        if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) {
                if (vcpu->guest_debug &
                    (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))
@@ -979,6 +985,16 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
                                1 << BP_VECTOR;
        } else
                vcpu->guest_debug = 0;
+}
+
+static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
+{
+       int old_debug = vcpu->guest_debug;
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       vcpu->guest_debug = dbg->control;
+
+       update_db_intercept(vcpu);
 
        if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
                svm->vmcb->save.dr7 = dbg->arch.debugreg[7];
@@ -993,16 +1009,6 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
        return 0;
 }
 
-static int svm_get_irq(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       u32 exit_int_info = svm->vmcb->control.exit_int_info;
-
-       if (is_external_interrupt(exit_int_info))
-               return exit_int_info & SVM_EVTINJ_VEC_MASK;
-       return -1;
-}
-
 static void load_host_msrs(struct kvm_vcpu *vcpu)
 {
 #ifdef CONFIG_X86_64
@@ -1107,17 +1113,8 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
 
 static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
-       u32 exit_int_info = svm->vmcb->control.exit_int_info;
-       struct kvm *kvm = svm->vcpu.kvm;
        u64 fault_address;
        u32 error_code;
-       bool event_injection = false;
-
-       if (!irqchip_in_kernel(kvm) &&
-           is_external_interrupt(exit_int_info)) {
-               event_injection = true;
-               push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
-       }
 
        fault_address  = svm->vmcb->control.exit_info_2;
        error_code = svm->vmcb->control.exit_info_1;
@@ -1137,23 +1134,40 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
         */
        if (npt_enabled)
                svm_flush_tlb(&svm->vcpu);
-
-       if (!npt_enabled && event_injection)
-               kvm_mmu_unprotect_page_virt(&svm->vcpu, fault_address);
+       else {
+               if (kvm_event_needs_reinjection(&svm->vcpu))
+                       kvm_mmu_unprotect_page_virt(&svm->vcpu, fault_address);
+       }
        return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code);
 }
 
 static int db_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
        if (!(svm->vcpu.guest_debug &
-             (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) {
+             (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) &&
+               !svm->vcpu.arch.singlestep) {
                kvm_queue_exception(&svm->vcpu, DB_VECTOR);
                return 1;
        }
-       kvm_run->exit_reason = KVM_EXIT_DEBUG;
-       kvm_run->debug.arch.pc = svm->vmcb->save.cs.base + svm->vmcb->save.rip;
-       kvm_run->debug.arch.exception = DB_VECTOR;
-       return 0;
+
+       if (svm->vcpu.arch.singlestep) {
+               svm->vcpu.arch.singlestep = false;
+               if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP))
+                       svm->vmcb->save.rflags &=
+                               ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
+               update_db_intercept(&svm->vcpu);
+       }
+
+       if (svm->vcpu.guest_debug &
+           (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)){
+               kvm_run->exit_reason = KVM_EXIT_DEBUG;
+               kvm_run->debug.arch.pc =
+                       svm->vmcb->save.cs.base + svm->vmcb->save.rip;
+               kvm_run->debug.arch.exception = DB_VECTOR;
+               return 0;
+       }
+
+       return 1;
 }
 
 static int bp_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
@@ -1842,17 +1856,51 @@ static int task_switch_interception(struct vcpu_svm *svm,
                                    struct kvm_run *kvm_run)
 {
        u16 tss_selector;
+       int reason;
+       int int_type = svm->vmcb->control.exit_int_info &
+               SVM_EXITINTINFO_TYPE_MASK;
+       int int_vec = svm->vmcb->control.exit_int_info & SVM_EVTINJ_VEC_MASK;
+       uint32_t type =
+               svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_TYPE_MASK;
+       uint32_t idt_v =
+               svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID;
 
        tss_selector = (u16)svm->vmcb->control.exit_info_1;
+
        if (svm->vmcb->control.exit_info_2 &
            (1ULL << SVM_EXITINFOSHIFT_TS_REASON_IRET))
-               return kvm_task_switch(&svm->vcpu, tss_selector,
-                                      TASK_SWITCH_IRET);
-       if (svm->vmcb->control.exit_info_2 &
-           (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP))
-               return kvm_task_switch(&svm->vcpu, tss_selector,
-                                      TASK_SWITCH_JMP);
-       return kvm_task_switch(&svm->vcpu, tss_selector, TASK_SWITCH_CALL);
+               reason = TASK_SWITCH_IRET;
+       else if (svm->vmcb->control.exit_info_2 &
+                (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP))
+               reason = TASK_SWITCH_JMP;
+       else if (idt_v)
+               reason = TASK_SWITCH_GATE;
+       else
+               reason = TASK_SWITCH_CALL;
+
+       if (reason == TASK_SWITCH_GATE) {
+               switch (type) {
+               case SVM_EXITINTINFO_TYPE_NMI:
+                       svm->vcpu.arch.nmi_injected = false;
+                       break;
+               case SVM_EXITINTINFO_TYPE_EXEPT:
+                       kvm_clear_exception_queue(&svm->vcpu);
+                       break;
+               case SVM_EXITINTINFO_TYPE_INTR:
+                       kvm_clear_interrupt_queue(&svm->vcpu);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if (reason != TASK_SWITCH_GATE ||
+           int_type == SVM_EXITINTINFO_TYPE_SOFT ||
+           (int_type == SVM_EXITINTINFO_TYPE_EXEPT &&
+            (int_vec == OF_VECTOR || int_vec == BP_VECTOR)))
+               skip_emulated_instruction(&svm->vcpu);
+
+       return kvm_task_switch(&svm->vcpu, tss_selector, reason);
 }
 
 static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
@@ -1862,6 +1910,14 @@ static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        return 1;
 }
 
+static int iret_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+{
+       ++svm->vcpu.stat.nmi_window_exits;
+       svm->vmcb->control.intercept &= ~(1UL << INTERCEPT_IRET);
+       svm->vcpu.arch.hflags |= HF_IRET_MASK;
+       return 1;
+}
+
 static int invlpg_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
        if (emulate_instruction(&svm->vcpu, kvm_run, 0, 0, 0) != EMULATE_DONE)
@@ -1879,8 +1935,14 @@ static int emulate_on_interception(struct vcpu_svm *svm,
 
 static int cr8_write_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
+       u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
+       /* instruction emulation calls kvm_set_cr8() */
        emulate_instruction(&svm->vcpu, NULL, 0, 0, 0);
-       if (irqchip_in_kernel(svm->vcpu.kvm))
+       if (irqchip_in_kernel(svm->vcpu.kvm)) {
+               svm->vmcb->control.intercept_cr_write &= ~INTERCEPT_CR8_MASK;
+               return 1;
+       }
+       if (cr8_prev <= kvm_get_cr8(&svm->vcpu))
                return 1;
        kvm_run->exit_reason = KVM_EXIT_SET_TPR;
        return 0;
@@ -2090,8 +2152,9 @@ static int interrupt_window_interception(struct vcpu_svm *svm,
         * If the user space waits to inject interrupts, exit as soon as
         * possible
         */
-       if (kvm_run->request_interrupt_window &&
-           !svm->vcpu.arch.irq_summary) {
+       if (!irqchip_in_kernel(svm->vcpu.kvm) &&
+           kvm_run->request_interrupt_window &&
+           !kvm_cpu_has_interrupt(&svm->vcpu)) {
                ++svm->vcpu.stat.irq_window_exits;
                kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
                return 0;
@@ -2134,6 +2197,7 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
        [SVM_EXIT_VINTR]                        = interrupt_window_interception,
        /* [SVM_EXIT_CR0_SEL_WRITE]             = emulate_on_interception, */
        [SVM_EXIT_CPUID]                        = cpuid_interception,
+       [SVM_EXIT_IRET]                         = iret_interception,
        [SVM_EXIT_INVD]                         = emulate_on_interception,
        [SVM_EXIT_HLT]                          = halt_interception,
        [SVM_EXIT_INVLPG]                       = invlpg_interception,
@@ -2194,7 +2258,6 @@ static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
                }
        }
 
-       kvm_reput_irq(svm);
 
        if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
                kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
@@ -2205,7 +2268,7 @@ static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
        if (is_external_interrupt(svm->vmcb->control.exit_int_info) &&
            exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR &&
-           exit_code != SVM_EXIT_NPF)
+           exit_code != SVM_EXIT_NPF && exit_code != SVM_EXIT_TASK_SWITCH)
                printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x "
                       "exit_code 0x%x\n",
                       __func__, svm->vmcb->control.exit_int_info,
@@ -2242,6 +2305,15 @@ static void pre_svm_run(struct vcpu_svm *svm)
                new_asid(svm, svm_data);
 }
 
+static void svm_inject_nmi(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_NMI;
+       vcpu->arch.hflags |= HF_NMI_MASK;
+       svm->vmcb->control.intercept |= (1UL << INTERCEPT_IRET);
+       ++vcpu->stat.nmi_injections;
+}
 
 static inline void svm_inject_irq(struct vcpu_svm *svm, int irq)
 {
@@ -2257,134 +2329,71 @@ static inline void svm_inject_irq(struct vcpu_svm *svm, int irq)
                ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT);
 }
 
-static void svm_set_irq(struct kvm_vcpu *vcpu, int irq)
+static void svm_queue_irq(struct kvm_vcpu *vcpu, unsigned nr)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       nested_svm_intr(svm);
-
-       svm_inject_irq(svm, irq);
+       svm->vmcb->control.event_inj = nr |
+               SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
 }
 
-static void update_cr8_intercept(struct kvm_vcpu *vcpu)
+static void svm_set_irq(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
-       struct vmcb *vmcb = svm->vmcb;
-       int max_irr, tpr;
 
-       if (!irqchip_in_kernel(vcpu->kvm) || vcpu->arch.apic->vapic_addr)
-               return;
+       nested_svm_intr(svm);
 
-       vmcb->control.intercept_cr_write &= ~INTERCEPT_CR8_MASK;
+       svm_queue_irq(vcpu, vcpu->arch.interrupt.nr);
+}
 
-       max_irr = kvm_lapic_find_highest_irr(vcpu);
-       if (max_irr == -1)
-               return;
+static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
 
-       tpr = kvm_lapic_get_cr8(vcpu) << 4;
+       if (irr == -1)
+               return;
 
-       if (tpr >= (max_irr & 0xf0))
-               vmcb->control.intercept_cr_write |= INTERCEPT_CR8_MASK;
+       if (tpr >= irr)
+               svm->vmcb->control.intercept_cr_write |= INTERCEPT_CR8_MASK;
 }
 
-static void svm_intr_assist(struct kvm_vcpu *vcpu)
+static int svm_nmi_allowed(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
        struct vmcb *vmcb = svm->vmcb;
-       int intr_vector = -1;
-
-       if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) &&
-           ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) {
-               intr_vector = vmcb->control.exit_int_info &
-                             SVM_EVTINJ_VEC_MASK;
-               vmcb->control.exit_int_info = 0;
-               svm_inject_irq(svm, intr_vector);
-               goto out;
-       }
-
-       if (vmcb->control.int_ctl & V_IRQ_MASK)
-               goto out;
-
-       if (!kvm_cpu_has_interrupt(vcpu))
-               goto out;
-
-       if (nested_svm_intr(svm))
-               goto out;
-
-       if (!(svm->vcpu.arch.hflags & HF_GIF_MASK))
-               goto out;
-
-       if (!(vmcb->save.rflags & X86_EFLAGS_IF) ||
-           (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) ||
-           (vmcb->control.event_inj & SVM_EVTINJ_VALID)) {
-               /* unable to deliver irq, set pending irq */
-               svm_set_vintr(svm);
-               svm_inject_irq(svm, 0x0);
-               goto out;
-       }
-       /* Okay, we can deliver the interrupt: grab it and update PIC state. */
-       intr_vector = kvm_cpu_get_interrupt(vcpu);
-       svm_inject_irq(svm, intr_vector);
-out:
-       update_cr8_intercept(vcpu);
+       return !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) &&
+               !(svm->vcpu.arch.hflags & HF_NMI_MASK);
 }
 
-static void kvm_reput_irq(struct vcpu_svm *svm)
+static int svm_interrupt_allowed(struct kvm_vcpu *vcpu)
 {
-       struct vmcb_control_area *control = &svm->vmcb->control;
-
-       if ((control->int_ctl & V_IRQ_MASK)
-           && !irqchip_in_kernel(svm->vcpu.kvm)) {
-               control->int_ctl &= ~V_IRQ_MASK;
-               push_irq(&svm->vcpu, control->int_vector);
-       }
-
-       svm->vcpu.arch.interrupt_window_open =
-               !(control->int_state & SVM_INTERRUPT_SHADOW_MASK) &&
-                (svm->vcpu.arch.hflags & HF_GIF_MASK);
+       struct vcpu_svm *svm = to_svm(vcpu);
+       struct vmcb *vmcb = svm->vmcb;
+       return (vmcb->save.rflags & X86_EFLAGS_IF) &&
+               !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) &&
+               (svm->vcpu.arch.hflags & HF_GIF_MASK);
 }
 
-static void svm_do_inject_vector(struct vcpu_svm *svm)
+static void enable_irq_window(struct kvm_vcpu *vcpu)
 {
-       struct kvm_vcpu *vcpu = &svm->vcpu;
-       int word_index = __ffs(vcpu->arch.irq_summary);
-       int bit_index = __ffs(vcpu->arch.irq_pending[word_index]);
-       int irq = word_index * BITS_PER_LONG + bit_index;
-
-       clear_bit(bit_index, &vcpu->arch.irq_pending[word_index]);
-       if (!vcpu->arch.irq_pending[word_index])
-               clear_bit(word_index, &vcpu->arch.irq_summary);
-       svm_inject_irq(svm, irq);
+       svm_set_vintr(to_svm(vcpu));
+       svm_inject_irq(to_svm(vcpu), 0x0);
 }
 
-static void do_interrupt_requests(struct kvm_vcpu *vcpu,
-                                      struct kvm_run *kvm_run)
+static void enable_nmi_window(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
-       struct vmcb_control_area *control = &svm->vmcb->control;
-
-       if (nested_svm_intr(svm))
-               return;
 
-       svm->vcpu.arch.interrupt_window_open =
-               (!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) &&
-                (svm->vmcb->save.rflags & X86_EFLAGS_IF) &&
-                (svm->vcpu.arch.hflags & HF_GIF_MASK));
+       if ((svm->vcpu.arch.hflags & (HF_NMI_MASK | HF_IRET_MASK))
+           == HF_NMI_MASK)
+               return; /* IRET will cause a vm exit */
 
-       if (svm->vcpu.arch.interrupt_window_open && svm->vcpu.arch.irq_summary)
-               /*
-                * If interrupts enabled, and not blocked by sti or mov ss. Good.
-                */
-               svm_do_inject_vector(svm);
-
-       /*
-        * Interrupts blocked.  Wait for unblock.
-        */
-       if (!svm->vcpu.arch.interrupt_window_open &&
-           (svm->vcpu.arch.irq_summary || kvm_run->request_interrupt_window))
-               svm_set_vintr(svm);
-       else
-               svm_clear_vintr(svm);
+       /* Something prevents NMI from been injected. Single step over
+          possible problem (IRET or exception injection or interrupt
+          shadow) */
+       vcpu->arch.singlestep = true;
+       svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF);
+       update_db_intercept(vcpu);
 }
 
 static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr)
@@ -2407,7 +2416,7 @@ static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu)
 
        if (!(svm->vmcb->control.intercept_cr_write & INTERCEPT_CR8_MASK)) {
                int cr8 = svm->vmcb->control.int_ctl & V_TPR_MASK;
-               kvm_lapic_set_tpr(vcpu, cr8);
+               kvm_set_cr8(vcpu, cr8);
        }
 }
 
@@ -2416,14 +2425,54 @@ static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu)
        struct vcpu_svm *svm = to_svm(vcpu);
        u64 cr8;
 
-       if (!irqchip_in_kernel(vcpu->kvm))
-               return;
-
        cr8 = kvm_get_cr8(vcpu);
        svm->vmcb->control.int_ctl &= ~V_TPR_MASK;
        svm->vmcb->control.int_ctl |= cr8 & V_TPR_MASK;
 }
 
+static void svm_complete_interrupts(struct vcpu_svm *svm)
+{
+       u8 vector;
+       int type;
+       u32 exitintinfo = svm->vmcb->control.exit_int_info;
+
+       if (svm->vcpu.arch.hflags & HF_IRET_MASK)
+               svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK);
+
+       svm->vcpu.arch.nmi_injected = false;
+       kvm_clear_exception_queue(&svm->vcpu);
+       kvm_clear_interrupt_queue(&svm->vcpu);
+
+       if (!(exitintinfo & SVM_EXITINTINFO_VALID))
+               return;
+
+       vector = exitintinfo & SVM_EXITINTINFO_VEC_MASK;
+       type = exitintinfo & SVM_EXITINTINFO_TYPE_MASK;
+
+       switch (type) {
+       case SVM_EXITINTINFO_TYPE_NMI:
+               svm->vcpu.arch.nmi_injected = true;
+               break;
+       case SVM_EXITINTINFO_TYPE_EXEPT:
+               /* In case of software exception do not reinject an exception
+                  vector, but re-execute and instruction instead */
+               if (kvm_exception_is_soft(vector))
+                       break;
+               if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) {
+                       u32 err = svm->vmcb->control.exit_int_info_err;
+                       kvm_queue_exception_e(&svm->vcpu, vector, err);
+
+               } else
+                       kvm_queue_exception(&svm->vcpu, vector);
+               break;
+       case SVM_EXITINTINFO_TYPE_INTR:
+               kvm_queue_interrupt(&svm->vcpu, vector, false);
+               break;
+       default:
+               break;
+       }
+}
+
 #ifdef CONFIG_X86_64
 #define R "r"
 #else
@@ -2552,6 +2601,8 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        sync_cr8_to_lapic(vcpu);
 
        svm->next_rip = 0;
+
+       svm_complete_interrupts(svm);
 }
 
 #undef R
@@ -2617,7 +2668,7 @@ static int get_npt_level(void)
 #endif
 }
 
-static int svm_get_mt_mask_shift(void)
+static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
 {
        return 0;
 }
@@ -2667,17 +2718,21 @@ static struct kvm_x86_ops svm_x86_ops = {
        .run = svm_vcpu_run,
        .handle_exit = handle_exit,
        .skip_emulated_instruction = skip_emulated_instruction,
+       .set_interrupt_shadow = svm_set_interrupt_shadow,
+       .get_interrupt_shadow = svm_get_interrupt_shadow,
        .patch_hypercall = svm_patch_hypercall,
-       .get_irq = svm_get_irq,
        .set_irq = svm_set_irq,
+       .set_nmi = svm_inject_nmi,
        .queue_exception = svm_queue_exception,
-       .exception_injected = svm_exception_injected,
-       .inject_pending_irq = svm_intr_assist,
-       .inject_pending_vectors = do_interrupt_requests,
+       .interrupt_allowed = svm_interrupt_allowed,
+       .nmi_allowed = svm_nmi_allowed,
+       .enable_nmi_window = enable_nmi_window,
+       .enable_irq_window = enable_irq_window,
+       .update_cr8_intercept = update_cr8_intercept,
 
        .set_tss_addr = svm_set_tss_addr,
        .get_tdp_level = get_npt_level,
-       .get_mt_mask_shift = svm_get_mt_mask_shift,
+       .get_mt_mask = svm_get_mt_mask,
 };
 
 static int __init svm_init(void)
diff --git a/arch/x86/kvm/timer.c b/arch/x86/kvm/timer.c
new file mode 100644 (file)
index 0000000..86dbac0
--- /dev/null
@@ -0,0 +1,46 @@
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+#include <linux/hrtimer.h>
+#include <asm/atomic.h>
+#include "kvm_timer.h"
+
+static int __kvm_timer_fn(struct kvm_vcpu *vcpu, struct kvm_timer *ktimer)
+{
+       int restart_timer = 0;
+       wait_queue_head_t *q = &vcpu->wq;
+
+       /* FIXME: this code should not know anything about vcpus */
+       if (!atomic_inc_and_test(&ktimer->pending))
+               set_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests);
+
+       if (!ktimer->reinject)
+               atomic_set(&ktimer->pending, 1);
+
+       if (waitqueue_active(q))
+               wake_up_interruptible(q);
+
+       if (ktimer->t_ops->is_periodic(ktimer)) {
+               hrtimer_add_expires_ns(&ktimer->timer, ktimer->period);
+               restart_timer = 1;
+       }
+
+       return restart_timer;
+}
+
+enum hrtimer_restart kvm_timer_fn(struct hrtimer *data)
+{
+       int restart_timer;
+       struct kvm_vcpu *vcpu;
+       struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer);
+
+       vcpu = ktimer->kvm->vcpus[ktimer->vcpu_id];
+       if (!vcpu)
+               return HRTIMER_NORESTART;
+
+       restart_timer = __kvm_timer_fn(vcpu, ktimer);
+       if (restart_timer)
+               return HRTIMER_RESTART;
+       else
+               return HRTIMER_NORESTART;
+}
+
index bb481330716f5eb92108aa4fbc4b93549211ceec..32d6ae8fb60e339eba6b85968676776d44293c8b 100644 (file)
 #include <asm/desc.h>
 #include <asm/vmx.h>
 #include <asm/virtext.h>
+#include <asm/mce.h>
 
 #define __ex(x) __kvm_handle_fault_on_reboot(x)
 
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
-static int bypass_guest_pf = 1;
-module_param(bypass_guest_pf, bool, 0);
+static int __read_mostly bypass_guest_pf = 1;
+module_param(bypass_guest_pf, bool, S_IRUGO);
 
-static int enable_vpid = 1;
-module_param(enable_vpid, bool, 0);
+static int __read_mostly enable_vpid = 1;
+module_param_named(vpid, enable_vpid, bool, 0444);
 
-static int flexpriority_enabled = 1;
-module_param(flexpriority_enabled, bool, 0);
+static int __read_mostly flexpriority_enabled = 1;
+module_param_named(flexpriority, flexpriority_enabled, bool, S_IRUGO);
 
-static int enable_ept = 1;
-module_param(enable_ept, bool, 0);
+static int __read_mostly enable_ept = 1;
+module_param_named(ept, enable_ept, bool, S_IRUGO);
 
-static int emulate_invalid_guest_state = 0;
-module_param(emulate_invalid_guest_state, bool, 0);
+static int __read_mostly emulate_invalid_guest_state = 0;
+module_param(emulate_invalid_guest_state, bool, S_IRUGO);
 
 struct vmcs {
        u32 revision_id;
@@ -97,6 +98,7 @@ struct vcpu_vmx {
        int soft_vnmi_blocked;
        ktime_t entry_time;
        s64 vnmi_blocked_time;
+       u32 exit_reason;
 };
 
 static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
@@ -111,9 +113,10 @@ static DEFINE_PER_CPU(struct vmcs *, vmxarea);
 static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
 static DEFINE_PER_CPU(struct list_head, vcpus_on_cpu);
 
-static struct page *vmx_io_bitmap_a;
-static struct page *vmx_io_bitmap_b;
-static struct page *vmx_msr_bitmap;
+static unsigned long *vmx_io_bitmap_a;
+static unsigned long *vmx_io_bitmap_b;
+static unsigned long *vmx_msr_bitmap_legacy;
+static unsigned long *vmx_msr_bitmap_longmode;
 
 static DECLARE_BITMAP(vmx_vpid_bitmap, VMX_NR_VPIDS);
 static DEFINE_SPINLOCK(vmx_vpid_lock);
@@ -213,70 +216,78 @@ static inline int is_external_interrupt(u32 intr_info)
                == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
 }
 
+static inline int is_machine_check(u32 intr_info)
+{
+       return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
+                            INTR_INFO_VALID_MASK)) ==
+               (INTR_TYPE_HARD_EXCEPTION | MC_VECTOR | INTR_INFO_VALID_MASK);
+}
+
 static inline int cpu_has_vmx_msr_bitmap(void)
 {
-       return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS);
+       return vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS;
 }
 
 static inline int cpu_has_vmx_tpr_shadow(void)
 {
-       return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW);
+       return vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW;
 }
 
 static inline int vm_need_tpr_shadow(struct kvm *kvm)
 {
-       return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm)));
+       return (cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm));
 }
 
 static inline int cpu_has_secondary_exec_ctrls(void)
 {
-       return (vmcs_config.cpu_based_exec_ctrl &
-               CPU_BASED_ACTIVATE_SECONDARY_CONTROLS);
+       return vmcs_config.cpu_based_exec_ctrl &
+               CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
 }
 
 static inline bool cpu_has_vmx_virtualize_apic_accesses(void)
 {
-       return flexpriority_enabled
-               && (vmcs_config.cpu_based_2nd_exec_ctrl &
-                   SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES);
+       return vmcs_config.cpu_based_2nd_exec_ctrl &
+               SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
+}
+
+static inline bool cpu_has_vmx_flexpriority(void)
+{
+       return cpu_has_vmx_tpr_shadow() &&
+               cpu_has_vmx_virtualize_apic_accesses();
 }
 
 static inline int cpu_has_vmx_invept_individual_addr(void)
 {
-       return (!!(vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT));
+       return !!(vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT);
 }
 
 static inline int cpu_has_vmx_invept_context(void)
 {
-       return (!!(vmx_capability.ept & VMX_EPT_EXTENT_CONTEXT_BIT));
+       return !!(vmx_capability.ept & VMX_EPT_EXTENT_CONTEXT_BIT);
 }
 
 static inline int cpu_has_vmx_invept_global(void)
 {
-       return (!!(vmx_capability.ept & VMX_EPT_EXTENT_GLOBAL_BIT));
+       return !!(vmx_capability.ept & VMX_EPT_EXTENT_GLOBAL_BIT);
 }
 
 static inline int cpu_has_vmx_ept(void)
 {
-       return (vmcs_config.cpu_based_2nd_exec_ctrl &
-               SECONDARY_EXEC_ENABLE_EPT);
-}
-
-static inline int vm_need_ept(void)
-{
-       return (cpu_has_vmx_ept() && enable_ept);
+       return vmcs_config.cpu_based_2nd_exec_ctrl &
+               SECONDARY_EXEC_ENABLE_EPT;
 }
 
 static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm)
 {
-       return ((cpu_has_vmx_virtualize_apic_accesses()) &&
-               (irqchip_in_kernel(kvm)));
+       return flexpriority_enabled &&
+               (cpu_has_vmx_virtualize_apic_accesses()) &&
+               (irqchip_in_kernel(kvm));
 }
 
 static inline int cpu_has_vmx_vpid(void)
 {
-       return (vmcs_config.cpu_based_2nd_exec_ctrl &
-               SECONDARY_EXEC_ENABLE_VPID);
+       return vmcs_config.cpu_based_2nd_exec_ctrl &
+               SECONDARY_EXEC_ENABLE_VPID;
 }
 
 static inline int cpu_has_virtual_nmis(void)
@@ -284,6 +295,11 @@ static inline int cpu_has_virtual_nmis(void)
        return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS;
 }
 
+static inline bool report_flexpriority(void)
+{
+       return flexpriority_enabled;
+}
+
 static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
 {
        int i;
@@ -381,7 +397,7 @@ static inline void ept_sync_global(void)
 
 static inline void ept_sync_context(u64 eptp)
 {
-       if (vm_need_ept()) {
+       if (enable_ept) {
                if (cpu_has_vmx_invept_context())
                        __invept(VMX_EPT_EXTENT_CONTEXT, eptp, 0);
                else
@@ -391,7 +407,7 @@ static inline void ept_sync_context(u64 eptp)
 
 static inline void ept_sync_individual_addr(u64 eptp, gpa_t gpa)
 {
-       if (vm_need_ept()) {
+       if (enable_ept) {
                if (cpu_has_vmx_invept_individual_addr())
                        __invept(VMX_EPT_EXTENT_INDIVIDUAL_ADDR,
                                        eptp, gpa);
@@ -478,7 +494,7 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
 {
        u32 eb;
 
-       eb = (1u << PF_VECTOR) | (1u << UD_VECTOR);
+       eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR);
        if (!vcpu->fpu_active)
                eb |= 1u << NM_VECTOR;
        if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) {
@@ -488,9 +504,9 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
                if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
                        eb |= 1u << BP_VECTOR;
        }
-       if (vcpu->arch.rmode.active)
+       if (vcpu->arch.rmode.vm86_active)
                eb = ~0;
-       if (vm_need_ept())
+       if (enable_ept)
                eb &= ~(1u << PF_VECTOR); /* bypass_guest_pf = 0 */
        vmcs_write32(EXCEPTION_BITMAP, eb);
 }
@@ -724,29 +740,50 @@ static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
 
 static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
 {
-       if (vcpu->arch.rmode.active)
+       if (vcpu->arch.rmode.vm86_active)
                rflags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM;
        vmcs_writel(GUEST_RFLAGS, rflags);
 }
 
+static u32 vmx_get_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
+{
+       u32 interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
+       int ret = 0;
+
+       if (interruptibility & GUEST_INTR_STATE_STI)
+               ret |= X86_SHADOW_INT_STI;
+       if (interruptibility & GUEST_INTR_STATE_MOV_SS)
+               ret |= X86_SHADOW_INT_MOV_SS;
+
+       return ret & mask;
+}
+
+static void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
+{
+       u32 interruptibility_old = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
+       u32 interruptibility = interruptibility_old;
+
+       interruptibility &= ~(GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS);
+
+       if (mask & X86_SHADOW_INT_MOV_SS)
+               interruptibility |= GUEST_INTR_STATE_MOV_SS;
+       if (mask & X86_SHADOW_INT_STI)
+               interruptibility |= GUEST_INTR_STATE_STI;
+
+       if ((interruptibility != interruptibility_old))
+               vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, interruptibility);
+}
+
 static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
 {
        unsigned long rip;
-       u32 interruptibility;
 
        rip = kvm_rip_read(vcpu);
        rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
        kvm_rip_write(vcpu, rip);
 
-       /*
-        * We emulated an instruction, so temporary interrupt blocking
-        * should be removed, if set.
-        */
-       interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
-       if (interruptibility & 3)
-               vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
-                            interruptibility & ~3);
-       vcpu->arch.interrupt_window_open = 1;
+       /* skipping an emulated instruction also counts */
+       vmx_set_interrupt_shadow(vcpu, 0);
 }
 
 static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
@@ -760,7 +797,7 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
                intr_info |= INTR_INFO_DELIVER_CODE_MASK;
        }
 
-       if (vcpu->arch.rmode.active) {
+       if (vcpu->arch.rmode.vm86_active) {
                vmx->rmode.irq.pending = true;
                vmx->rmode.irq.vector = nr;
                vmx->rmode.irq.rip = kvm_rip_read(vcpu);
@@ -773,8 +810,9 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
                return;
        }
 
-       if (nr == BP_VECTOR || nr == OF_VECTOR) {
-               vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1);
+       if (kvm_exception_is_soft(nr)) {
+               vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
+                            vmx->vcpu.arch.event_exit_inst_len);
                intr_info |= INTR_TYPE_SOFT_EXCEPTION;
        } else
                intr_info |= INTR_TYPE_HARD_EXCEPTION;
@@ -782,11 +820,6 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
        vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info);
 }
 
-static bool vmx_exception_injected(struct kvm_vcpu *vcpu)
-{
-       return false;
-}
-
 /*
  * Swap MSR entry in host/guest MSR entry array.
  */
@@ -812,6 +845,7 @@ static void move_msr_up(struct vcpu_vmx *vmx, int from, int to)
 static void setup_msrs(struct vcpu_vmx *vmx)
 {
        int save_nmsrs;
+       unsigned long *msr_bitmap;
 
        vmx_load_host_state(vmx);
        save_nmsrs = 0;
@@ -847,6 +881,15 @@ static void setup_msrs(struct vcpu_vmx *vmx)
                __find_msr_index(vmx, MSR_KERNEL_GS_BASE);
 #endif
        vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER);
+
+       if (cpu_has_vmx_msr_bitmap()) {
+               if (is_long_mode(&vmx->vcpu))
+                       msr_bitmap = vmx_msr_bitmap_longmode;
+               else
+                       msr_bitmap = vmx_msr_bitmap_legacy;
+
+               vmcs_write64(MSR_BITMAP, __pa(msr_bitmap));
+       }
 }
 
 /*
@@ -1034,13 +1077,6 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
        return 0;
 }
 
-static int vmx_get_irq(struct kvm_vcpu *vcpu)
-{
-       if (!vcpu->arch.interrupt.pending)
-               return -1;
-       return vcpu->arch.interrupt.nr;
-}
-
 static __init int cpu_has_kvm_support(void)
 {
        return cpu_has_vmx();
@@ -1294,6 +1330,18 @@ static __init int hardware_setup(void)
        if (boot_cpu_has(X86_FEATURE_NX))
                kvm_enable_efer_bits(EFER_NX);
 
+       if (!cpu_has_vmx_vpid())
+               enable_vpid = 0;
+
+       if (!cpu_has_vmx_ept())
+               enable_ept = 0;
+
+       if (!cpu_has_vmx_flexpriority())
+               flexpriority_enabled = 0;
+
+       if (!cpu_has_vmx_tpr_shadow())
+               kvm_x86_ops->update_cr8_intercept = NULL;
+
        return alloc_kvm_area();
 }
 
@@ -1324,7 +1372,7 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
        vmx->emulation_required = 1;
-       vcpu->arch.rmode.active = 0;
+       vcpu->arch.rmode.vm86_active = 0;
 
        vmcs_writel(GUEST_TR_BASE, vcpu->arch.rmode.tr.base);
        vmcs_write32(GUEST_TR_LIMIT, vcpu->arch.rmode.tr.limit);
@@ -1386,7 +1434,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
        vmx->emulation_required = 1;
-       vcpu->arch.rmode.active = 1;
+       vcpu->arch.rmode.vm86_active = 1;
 
        vcpu->arch.rmode.tr.base = vmcs_readl(GUEST_TR_BASE);
        vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm));
@@ -1485,7 +1533,7 @@ static void exit_lmode(struct kvm_vcpu *vcpu)
 static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
 {
        vpid_sync_vcpu_all(to_vmx(vcpu));
-       if (vm_need_ept())
+       if (enable_ept)
                ept_sync_context(construct_eptp(vcpu->arch.mmu.root_hpa));
 }
 
@@ -1555,10 +1603,10 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 
        vmx_fpu_deactivate(vcpu);
 
-       if (vcpu->arch.rmode.active && (cr0 & X86_CR0_PE))
+       if (vcpu->arch.rmode.vm86_active && (cr0 & X86_CR0_PE))
                enter_pmode(vcpu);
 
-       if (!vcpu->arch.rmode.active && !(cr0 & X86_CR0_PE))
+       if (!vcpu->arch.rmode.vm86_active && !(cr0 & X86_CR0_PE))
                enter_rmode(vcpu);
 
 #ifdef CONFIG_X86_64
@@ -1570,7 +1618,7 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
        }
 #endif
 
-       if (vm_need_ept())
+       if (enable_ept)
                ept_update_paging_mode_cr0(&hw_cr0, cr0, vcpu);
 
        vmcs_writel(CR0_READ_SHADOW, cr0);
@@ -1599,7 +1647,7 @@ static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
        u64 eptp;
 
        guest_cr3 = cr3;
-       if (vm_need_ept()) {
+       if (enable_ept) {
                eptp = construct_eptp(cr3);
                vmcs_write64(EPT_POINTER, eptp);
                ept_sync_context(eptp);
@@ -1616,11 +1664,11 @@ static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
 
 static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 {
-       unsigned long hw_cr4 = cr4 | (vcpu->arch.rmode.active ?
+       unsigned long hw_cr4 = cr4 | (vcpu->arch.rmode.vm86_active ?
                    KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON);
 
        vcpu->arch.cr4 = cr4;
-       if (vm_need_ept())
+       if (enable_ept)
                ept_update_paging_mode_cr4(&hw_cr4, vcpu);
 
        vmcs_writel(CR4_READ_SHADOW, cr4);
@@ -1699,7 +1747,7 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
        struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
        u32 ar;
 
-       if (vcpu->arch.rmode.active && seg == VCPU_SREG_TR) {
+       if (vcpu->arch.rmode.vm86_active && seg == VCPU_SREG_TR) {
                vcpu->arch.rmode.tr.selector = var->selector;
                vcpu->arch.rmode.tr.base = var->base;
                vcpu->arch.rmode.tr.limit = var->limit;
@@ -1709,7 +1757,7 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
        vmcs_writel(sf->base, var->base);
        vmcs_write32(sf->limit, var->limit);
        vmcs_write16(sf->selector, var->selector);
-       if (vcpu->arch.rmode.active && var->s) {
+       if (vcpu->arch.rmode.vm86_active && var->s) {
                /*
                 * Hack real-mode segments into vm86 compatibility.
                 */
@@ -1982,7 +2030,7 @@ static int init_rmode_identity_map(struct kvm *kvm)
        pfn_t identity_map_pfn;
        u32 tmp;
 
-       if (!vm_need_ept())
+       if (!enable_ept)
                return 1;
        if (unlikely(!kvm->arch.ept_identity_pagetable)) {
                printk(KERN_ERR "EPT: identity-mapping pagetable "
@@ -2071,7 +2119,7 @@ static void allocate_vpid(struct vcpu_vmx *vmx)
        int vpid;
 
        vmx->vpid = 0;
-       if (!enable_vpid || !cpu_has_vmx_vpid())
+       if (!enable_vpid)
                return;
        spin_lock(&vmx_vpid_lock);
        vpid = find_first_zero_bit(vmx_vpid_bitmap, VMX_NR_VPIDS);
@@ -2082,9 +2130,9 @@ static void allocate_vpid(struct vcpu_vmx *vmx)
        spin_unlock(&vmx_vpid_lock);
 }
 
-static void vmx_disable_intercept_for_msr(struct page *msr_bitmap, u32 msr)
+static void __vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, u32 msr)
 {
-       void *va;
+       int f = sizeof(unsigned long);
 
        if (!cpu_has_vmx_msr_bitmap())
                return;
@@ -2094,16 +2142,21 @@ static void vmx_disable_intercept_for_msr(struct page *msr_bitmap, u32 msr)
         * have the write-low and read-high bitmap offsets the wrong way round.
         * We can control MSRs 0x00000000-0x00001fff and 0xc0000000-0xc0001fff.
         */
-       va = kmap(msr_bitmap);
        if (msr <= 0x1fff) {
-               __clear_bit(msr, va + 0x000); /* read-low */
-               __clear_bit(msr, va + 0x800); /* write-low */
+               __clear_bit(msr, msr_bitmap + 0x000 / f); /* read-low */
+               __clear_bit(msr, msr_bitmap + 0x800 / f); /* write-low */
        } else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
                msr &= 0x1fff;
-               __clear_bit(msr, va + 0x400); /* read-high */
-               __clear_bit(msr, va + 0xc00); /* write-high */
+               __clear_bit(msr, msr_bitmap + 0x400 / f); /* read-high */
+               __clear_bit(msr, msr_bitmap + 0xc00 / f); /* write-high */
        }
-       kunmap(msr_bitmap);
+}
+
+static void vmx_disable_intercept_for_msr(u32 msr, bool longmode_only)
+{
+       if (!longmode_only)
+               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy, msr);
+       __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode, msr);
 }
 
 /*
@@ -2121,11 +2174,11 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
        u32 exec_control;
 
        /* I/O */
-       vmcs_write64(IO_BITMAP_A, page_to_phys(vmx_io_bitmap_a));
-       vmcs_write64(IO_BITMAP_B, page_to_phys(vmx_io_bitmap_b));
+       vmcs_write64(IO_BITMAP_A, __pa(vmx_io_bitmap_a));
+       vmcs_write64(IO_BITMAP_B, __pa(vmx_io_bitmap_b));
 
        if (cpu_has_vmx_msr_bitmap())
-               vmcs_write64(MSR_BITMAP, page_to_phys(vmx_msr_bitmap));
+               vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap_legacy));
 
        vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */
 
@@ -2141,7 +2194,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
                                CPU_BASED_CR8_LOAD_EXITING;
 #endif
        }
-       if (!vm_need_ept())
+       if (!enable_ept)
                exec_control |= CPU_BASED_CR3_STORE_EXITING |
                                CPU_BASED_CR3_LOAD_EXITING  |
                                CPU_BASED_INVLPG_EXITING;
@@ -2154,7 +2207,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
                                ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
                if (vmx->vpid == 0)
                        exec_control &= ~SECONDARY_EXEC_ENABLE_VPID;
-               if (!vm_need_ept())
+               if (!enable_ept)
                        exec_control &= ~SECONDARY_EXEC_ENABLE_EPT;
                vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control);
        }
@@ -2273,7 +2326,7 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
                goto out;
        }
 
-       vmx->vcpu.arch.rmode.active = 0;
+       vmx->vcpu.arch.rmode.vm86_active = 0;
 
        vmx->soft_vnmi_blocked = 0;
 
@@ -2402,14 +2455,16 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu)
        vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
 }
 
-static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq)
+static void vmx_inject_irq(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
+       uint32_t intr;
+       int irq = vcpu->arch.interrupt.nr;
 
        KVMTRACE_1D(INJ_VIRQ, vcpu, (u32)irq, handler);
 
        ++vcpu->stat.irq_injections;
-       if (vcpu->arch.rmode.active) {
+       if (vcpu->arch.rmode.vm86_active) {
                vmx->rmode.irq.pending = true;
                vmx->rmode.irq.vector = irq;
                vmx->rmode.irq.rip = kvm_rip_read(vcpu);
@@ -2419,8 +2474,14 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq)
                kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1);
                return;
        }
-       vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
-                       irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
+       intr = irq | INTR_INFO_VALID_MASK;
+       if (vcpu->arch.interrupt.soft) {
+               intr |= INTR_TYPE_SOFT_INTR;
+               vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
+                            vmx->vcpu.arch.event_exit_inst_len);
+       } else
+               intr |= INTR_TYPE_EXT_INTR;
+       vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr);
 }
 
 static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
@@ -2441,7 +2502,7 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
        }
 
        ++vcpu->stat.nmi_injections;
-       if (vcpu->arch.rmode.active) {
+       if (vcpu->arch.rmode.vm86_active) {
                vmx->rmode.irq.pending = true;
                vmx->rmode.irq.vector = NMI_VECTOR;
                vmx->rmode.irq.rip = kvm_rip_read(vcpu);
@@ -2456,76 +2517,21 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
                        INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK | NMI_VECTOR);
 }
 
-static void vmx_update_window_states(struct kvm_vcpu *vcpu)
+static int vmx_nmi_allowed(struct kvm_vcpu *vcpu)
 {
-       u32 guest_intr = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
-
-       vcpu->arch.nmi_window_open =
-               !(guest_intr & (GUEST_INTR_STATE_STI |
-                               GUEST_INTR_STATE_MOV_SS |
-                               GUEST_INTR_STATE_NMI));
        if (!cpu_has_virtual_nmis() && to_vmx(vcpu)->soft_vnmi_blocked)
-               vcpu->arch.nmi_window_open = 0;
-
-       vcpu->arch.interrupt_window_open =
-               ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
-                !(guest_intr & (GUEST_INTR_STATE_STI |
-                                GUEST_INTR_STATE_MOV_SS)));
-}
-
-static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
-{
-       int word_index = __ffs(vcpu->arch.irq_summary);
-       int bit_index = __ffs(vcpu->arch.irq_pending[word_index]);
-       int irq = word_index * BITS_PER_LONG + bit_index;
+               return 0;
 
-       clear_bit(bit_index, &vcpu->arch.irq_pending[word_index]);
-       if (!vcpu->arch.irq_pending[word_index])
-               clear_bit(word_index, &vcpu->arch.irq_summary);
-       kvm_queue_interrupt(vcpu, irq);
+       return  !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
+                       (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS |
+                               GUEST_INTR_STATE_NMI));
 }
 
-static void do_interrupt_requests(struct kvm_vcpu *vcpu,
-                                      struct kvm_run *kvm_run)
+static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu)
 {
-       vmx_update_window_states(vcpu);
-
-       if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
-               vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO,
-                               GUEST_INTR_STATE_STI |
-                               GUEST_INTR_STATE_MOV_SS);
-
-       if (vcpu->arch.nmi_pending && !vcpu->arch.nmi_injected) {
-               if (vcpu->arch.interrupt.pending) {
-                       enable_nmi_window(vcpu);
-               } else if (vcpu->arch.nmi_window_open) {
-                       vcpu->arch.nmi_pending = false;
-                       vcpu->arch.nmi_injected = true;
-               } else {
-                       enable_nmi_window(vcpu);
-                       return;
-               }
-       }
-       if (vcpu->arch.nmi_injected) {
-               vmx_inject_nmi(vcpu);
-               if (vcpu->arch.nmi_pending)
-                       enable_nmi_window(vcpu);
-               else if (vcpu->arch.irq_summary
-                        || kvm_run->request_interrupt_window)
-                       enable_irq_window(vcpu);
-               return;
-       }
-
-       if (vcpu->arch.interrupt_window_open) {
-               if (vcpu->arch.irq_summary && !vcpu->arch.interrupt.pending)
-                       kvm_do_inject_irq(vcpu);
-
-               if (vcpu->arch.interrupt.pending)
-                       vmx_inject_irq(vcpu, vcpu->arch.interrupt.nr);
-       }
-       if (!vcpu->arch.interrupt_window_open &&
-           (vcpu->arch.irq_summary || kvm_run->request_interrupt_window))
-               enable_irq_window(vcpu);
+       return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
+               !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
+                       (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS));
 }
 
 static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr)
@@ -2585,6 +2591,31 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu,
        return 0;
 }
 
+/*
+ * Trigger machine check on the host. We assume all the MSRs are already set up
+ * by the CPU and that we still run on the same CPU as the MCE occurred on.
+ * We pass a fake environment to the machine check handler because we want
+ * the guest to be always treated like user space, no matter what context
+ * it used internally.
+ */
+static void kvm_machine_check(void)
+{
+#if defined(CONFIG_X86_MCE) && defined(CONFIG_X86_64)
+       struct pt_regs regs = {
+               .cs = 3, /* Fake ring 3 no matter what the guest ran on */
+               .flags = X86_EFLAGS_IF,
+       };
+
+       do_machine_check(&regs, 0);
+#endif
+}
+
+static int handle_machine_check(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       /* already handled by vcpu_run */
+       return 1;
+}
+
 static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -2596,17 +2627,14 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        vect_info = vmx->idt_vectoring_info;
        intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
 
+       if (is_machine_check(intr_info))
+               return handle_machine_check(vcpu, kvm_run);
+
        if ((vect_info & VECTORING_INFO_VALID_MASK) &&
                                                !is_page_fault(intr_info))
                printk(KERN_ERR "%s: unexpected, vectoring info 0x%x "
                       "intr info 0x%x\n", __func__, vect_info, intr_info);
 
-       if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) {
-               int irq = vect_info & VECTORING_INFO_VECTOR_MASK;
-               set_bit(irq, vcpu->arch.irq_pending);
-               set_bit(irq / BITS_PER_LONG, &vcpu->arch.irq_summary);
-       }
-
        if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR)
                return 1;  /* already handled by vmx_vcpu_run() */
 
@@ -2628,17 +2656,17 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE);
        if (is_page_fault(intr_info)) {
                /* EPT won't cause page fault directly */
-               if (vm_need_ept())
+               if (enable_ept)
                        BUG();
                cr2 = vmcs_readl(EXIT_QUALIFICATION);
                KVMTRACE_3D(PAGE_FAULT, vcpu, error_code, (u32)cr2,
                            (u32)((u64)cr2 >> 32), handler);
-               if (vcpu->arch.interrupt.pending || vcpu->arch.exception.pending)
+               if (kvm_event_needs_reinjection(vcpu))
                        kvm_mmu_unprotect_page_virt(vcpu, cr2);
                return kvm_mmu_page_fault(vcpu, cr2, error_code);
        }
 
-       if (vcpu->arch.rmode.active &&
+       if (vcpu->arch.rmode.vm86_active &&
            handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK,
                                                                error_code)) {
                if (vcpu->arch.halt_request) {
@@ -2753,13 +2781,18 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                        kvm_set_cr4(vcpu, kvm_register_read(vcpu, reg));
                        skip_emulated_instruction(vcpu);
                        return 1;
-               case 8:
-                       kvm_set_cr8(vcpu, kvm_register_read(vcpu, reg));
-                       skip_emulated_instruction(vcpu);
-                       if (irqchip_in_kernel(vcpu->kvm))
-                               return 1;
-                       kvm_run->exit_reason = KVM_EXIT_SET_TPR;
-                       return 0;
+               case 8: {
+                               u8 cr8_prev = kvm_get_cr8(vcpu);
+                               u8 cr8 = kvm_register_read(vcpu, reg);
+                               kvm_set_cr8(vcpu, cr8);
+                               skip_emulated_instruction(vcpu);
+                               if (irqchip_in_kernel(vcpu->kvm))
+                                       return 1;
+                               if (cr8_prev <= cr8)
+                                       return 1;
+                               kvm_run->exit_reason = KVM_EXIT_SET_TPR;
+                               return 0;
+                       }
                };
                break;
        case 2: /* clts */
@@ -2957,8 +2990,9 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu,
         * If the user space waits to inject interrupts, exit as soon as
         * possible
         */
-       if (kvm_run->request_interrupt_window &&
-           !vcpu->arch.irq_summary) {
+       if (!irqchip_in_kernel(vcpu->kvm) &&
+           kvm_run->request_interrupt_window &&
+           !kvm_cpu_has_interrupt(vcpu)) {
                kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
                return 0;
        }
@@ -2980,7 +3014,7 @@ static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
 static int handle_invlpg(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
-       u64 exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+       unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
 
        kvm_mmu_invlpg(vcpu, exit_qualification);
        skip_emulated_instruction(vcpu);
@@ -2996,11 +3030,11 @@ static int handle_wbinvd(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
 static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
-       u64 exit_qualification;
+       unsigned long exit_qualification;
        enum emulation_result er;
        unsigned long offset;
 
-       exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+       exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
        offset = exit_qualification & 0xffful;
 
        er = emulate_instruction(vcpu, kvm_run, 0, 0, 0);
@@ -3019,22 +3053,41 @@ static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        unsigned long exit_qualification;
        u16 tss_selector;
-       int reason;
+       int reason, type, idt_v;
+
+       idt_v = (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK);
+       type = (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK);
 
        exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
 
        reason = (u32)exit_qualification >> 30;
-       if (reason == TASK_SWITCH_GATE && vmx->vcpu.arch.nmi_injected &&
-           (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK) &&
-           (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK)
-           == INTR_TYPE_NMI_INTR) {
-               vcpu->arch.nmi_injected = false;
-               if (cpu_has_virtual_nmis())
-                       vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
-                                     GUEST_INTR_STATE_NMI);
+       if (reason == TASK_SWITCH_GATE && idt_v) {
+               switch (type) {
+               case INTR_TYPE_NMI_INTR:
+                       vcpu->arch.nmi_injected = false;
+                       if (cpu_has_virtual_nmis())
+                               vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
+                                             GUEST_INTR_STATE_NMI);
+                       break;
+               case INTR_TYPE_EXT_INTR:
+               case INTR_TYPE_SOFT_INTR:
+                       kvm_clear_interrupt_queue(vcpu);
+                       break;
+               case INTR_TYPE_HARD_EXCEPTION:
+               case INTR_TYPE_SOFT_EXCEPTION:
+                       kvm_clear_exception_queue(vcpu);
+                       break;
+               default:
+                       break;
+               }
        }
        tss_selector = exit_qualification;
 
+       if (!idt_v || (type != INTR_TYPE_HARD_EXCEPTION &&
+                      type != INTR_TYPE_EXT_INTR &&
+                      type != INTR_TYPE_NMI_INTR))
+               skip_emulated_instruction(vcpu);
+
        if (!kvm_task_switch(vcpu, tss_selector, reason))
                return 0;
 
@@ -3051,11 +3104,11 @@ static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
 static int handle_ept_violation(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
-       u64 exit_qualification;
+       unsigned long exit_qualification;
        gpa_t gpa;
        int gla_validity;
 
-       exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+       exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
 
        if (exit_qualification & (1 << 6)) {
                printk(KERN_ERR "EPT: GPA exceeds GAW!\n");
@@ -3067,7 +3120,7 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                printk(KERN_ERR "EPT: Handling EPT violation failed!\n");
                printk(KERN_ERR "EPT: GPA: 0x%lx, GVA: 0x%lx\n",
                        (long unsigned int)vmcs_read64(GUEST_PHYSICAL_ADDRESS),
-                       (long unsigned int)vmcs_read64(GUEST_LINEAR_ADDRESS));
+                       vmcs_readl(GUEST_LINEAR_ADDRESS));
                printk(KERN_ERR "EPT: Exit qualification is 0x%lx\n",
                        (long unsigned int)exit_qualification);
                kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
@@ -3150,6 +3203,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
        [EXIT_REASON_WBINVD]                  = handle_wbinvd,
        [EXIT_REASON_TASK_SWITCH]             = handle_task_switch,
        [EXIT_REASON_EPT_VIOLATION]           = handle_ept_violation,
+       [EXIT_REASON_MCE_DURING_VMENTRY]      = handle_machine_check,
 };
 
 static const int kvm_vmx_max_exit_handlers =
@@ -3159,10 +3213,10 @@ static const int kvm_vmx_max_exit_handlers =
  * The guest has exited.  See if we can fix it or if we need userspace
  * assistance.
  */
-static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
+static int vmx_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
-       u32 exit_reason = vmcs_read32(VM_EXIT_REASON);
        struct vcpu_vmx *vmx = to_vmx(vcpu);
+       u32 exit_reason = vmx->exit_reason;
        u32 vectoring_info = vmx->idt_vectoring_info;
 
        KVMTRACE_3D(VMEXIT, vcpu, exit_reason, (u32)kvm_rip_read(vcpu),
@@ -3178,7 +3232,7 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
        /* Access CR3 don't cause VMExit in paging mode, so we need
         * to sync with guest real CR3. */
-       if (vm_need_ept() && is_paging(vcpu)) {
+       if (enable_ept && is_paging(vcpu)) {
                vcpu->arch.cr3 = vmcs_readl(GUEST_CR3);
                ept_load_pdptrs(vcpu);
        }
@@ -3199,9 +3253,8 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
                       __func__, vectoring_info, exit_reason);
 
        if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked)) {
-               if (vcpu->arch.interrupt_window_open) {
+               if (vmx_interrupt_allowed(vcpu)) {
                        vmx->soft_vnmi_blocked = 0;
-                       vcpu->arch.nmi_window_open = 1;
                } else if (vmx->vnmi_blocked_time > 1000000000LL &&
                           vcpu->arch.nmi_pending) {
                        /*
@@ -3214,7 +3267,6 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
                               "state on VCPU %d after 1 s timeout\n",
                               __func__, vcpu->vcpu_id);
                        vmx->soft_vnmi_blocked = 0;
-                       vmx->vcpu.arch.nmi_window_open = 1;
                }
        }
 
@@ -3228,122 +3280,107 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        return 0;
 }
 
-static void update_tpr_threshold(struct kvm_vcpu *vcpu)
+static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
 {
-       int max_irr, tpr;
-
-       if (!vm_need_tpr_shadow(vcpu->kvm))
-               return;
-
-       if (!kvm_lapic_enabled(vcpu) ||
-           ((max_irr = kvm_lapic_find_highest_irr(vcpu)) == -1)) {
+       if (irr == -1 || tpr < irr) {
                vmcs_write32(TPR_THRESHOLD, 0);
                return;
        }
 
-       tpr = (kvm_lapic_get_cr8(vcpu) & 0x0f) << 4;
-       vmcs_write32(TPR_THRESHOLD, (max_irr > tpr) ? tpr >> 4 : max_irr >> 4);
+       vmcs_write32(TPR_THRESHOLD, irr);
 }
 
 static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
 {
        u32 exit_intr_info;
-       u32 idt_vectoring_info;
+       u32 idt_vectoring_info = vmx->idt_vectoring_info;
        bool unblock_nmi;
        u8 vector;
        int type;
        bool idtv_info_valid;
-       u32 error;
 
        exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
+
+       vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);
+
+       /* Handle machine checks before interrupts are enabled */
+       if ((vmx->exit_reason == EXIT_REASON_MCE_DURING_VMENTRY)
+           || (vmx->exit_reason == EXIT_REASON_EXCEPTION_NMI
+               && is_machine_check(exit_intr_info)))
+               kvm_machine_check();
+
+       /* We need to handle NMIs before interrupts are enabled */
+       if ((exit_intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR &&
+           (exit_intr_info & INTR_INFO_VALID_MASK)) {
+               KVMTRACE_0D(NMI, &vmx->vcpu, handler);
+               asm("int $2");
+       }
+
+       idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK;
+
        if (cpu_has_virtual_nmis()) {
                unblock_nmi = (exit_intr_info & INTR_INFO_UNBLOCK_NMI) != 0;
                vector = exit_intr_info & INTR_INFO_VECTOR_MASK;
                /*
-                * SDM 3: 25.7.1.2
+                * SDM 3: 27.7.1.2 (September 2008)
                 * Re-set bit "block by NMI" before VM entry if vmexit caused by
                 * a guest IRET fault.
+                * SDM 3: 23.2.2 (September 2008)
+                * Bit 12 is undefined in any of the following cases:
+                *  If the VM exit sets the valid bit in the IDT-vectoring
+                *   information field.
+                *  If the VM exit is due to a double fault.
                 */
-               if (unblock_nmi && vector != DF_VECTOR)
+               if ((exit_intr_info & INTR_INFO_VALID_MASK) && unblock_nmi &&
+                   vector != DF_VECTOR && !idtv_info_valid)
                        vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
                                      GUEST_INTR_STATE_NMI);
        } else if (unlikely(vmx->soft_vnmi_blocked))
                vmx->vnmi_blocked_time +=
                        ktime_to_ns(ktime_sub(ktime_get(), vmx->entry_time));
 
-       idt_vectoring_info = vmx->idt_vectoring_info;
-       idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK;
+       vmx->vcpu.arch.nmi_injected = false;
+       kvm_clear_exception_queue(&vmx->vcpu);
+       kvm_clear_interrupt_queue(&vmx->vcpu);
+
+       if (!idtv_info_valid)
+               return;
+
        vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK;
        type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK;
-       if (vmx->vcpu.arch.nmi_injected) {
+
+       switch (type) {
+       case INTR_TYPE_NMI_INTR:
+               vmx->vcpu.arch.nmi_injected = true;
                /*
-                * SDM 3: 25.7.1.2
-                * Clear bit "block by NMI" before VM entry if a NMI delivery
-                * faulted.
+                * SDM 3: 27.7.1.2 (September 2008)
+                * Clear bit "block by NMI" before VM entry if a NMI
+                * delivery faulted.
                 */
-               if (idtv_info_valid && type == INTR_TYPE_NMI_INTR)
-                       vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO,
-                                       GUEST_INTR_STATE_NMI);
-               else
-                       vmx->vcpu.arch.nmi_injected = false;
-       }
-       kvm_clear_exception_queue(&vmx->vcpu);
-       if (idtv_info_valid && (type == INTR_TYPE_HARD_EXCEPTION ||
-                               type == INTR_TYPE_SOFT_EXCEPTION)) {
+               vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO,
+                               GUEST_INTR_STATE_NMI);
+               break;
+       case INTR_TYPE_SOFT_EXCEPTION:
+               vmx->vcpu.arch.event_exit_inst_len =
+                       vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+               /* fall through */
+       case INTR_TYPE_HARD_EXCEPTION:
                if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) {
-                       error = vmcs_read32(IDT_VECTORING_ERROR_CODE);
-                       kvm_queue_exception_e(&vmx->vcpu, vector, error);
+                       u32 err = vmcs_read32(IDT_VECTORING_ERROR_CODE);
+                       kvm_queue_exception_e(&vmx->vcpu, vector, err);
                } else
                        kvm_queue_exception(&vmx->vcpu, vector);
-               vmx->idt_vectoring_info = 0;
-       }
-       kvm_clear_interrupt_queue(&vmx->vcpu);
-       if (idtv_info_valid && type == INTR_TYPE_EXT_INTR) {
-               kvm_queue_interrupt(&vmx->vcpu, vector);
-               vmx->idt_vectoring_info = 0;
-       }
-}
-
-static void vmx_intr_assist(struct kvm_vcpu *vcpu)
-{
-       update_tpr_threshold(vcpu);
-
-       vmx_update_window_states(vcpu);
-
-       if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
-               vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO,
-                               GUEST_INTR_STATE_STI |
-                               GUEST_INTR_STATE_MOV_SS);
-
-       if (vcpu->arch.nmi_pending && !vcpu->arch.nmi_injected) {
-               if (vcpu->arch.interrupt.pending) {
-                       enable_nmi_window(vcpu);
-               } else if (vcpu->arch.nmi_window_open) {
-                       vcpu->arch.nmi_pending = false;
-                       vcpu->arch.nmi_injected = true;
-               } else {
-                       enable_nmi_window(vcpu);
-                       return;
-               }
-       }
-       if (vcpu->arch.nmi_injected) {
-               vmx_inject_nmi(vcpu);
-               if (vcpu->arch.nmi_pending)
-                       enable_nmi_window(vcpu);
-               else if (kvm_cpu_has_interrupt(vcpu))
-                       enable_irq_window(vcpu);
-               return;
-       }
-       if (!vcpu->arch.interrupt.pending && kvm_cpu_has_interrupt(vcpu)) {
-               if (vcpu->arch.interrupt_window_open)
-                       kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu));
-               else
-                       enable_irq_window(vcpu);
-       }
-       if (vcpu->arch.interrupt.pending) {
-               vmx_inject_irq(vcpu, vcpu->arch.interrupt.nr);
-               if (kvm_cpu_has_interrupt(vcpu))
-                       enable_irq_window(vcpu);
+               break;
+       case INTR_TYPE_SOFT_INTR:
+               vmx->vcpu.arch.event_exit_inst_len =
+                       vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+               /* fall through */
+       case INTR_TYPE_EXT_INTR:
+               kvm_queue_interrupt(&vmx->vcpu, vector,
+                       type == INTR_TYPE_SOFT_INTR);
+               break;
+       default:
+               break;
        }
 }
 
@@ -3381,7 +3418,6 @@ static void fixup_rmode_irq(struct vcpu_vmx *vmx)
 static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
-       u32 intr_info;
 
        /* Record the guest's net vcpu time for enforced NMI injections. */
        if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked))
@@ -3505,20 +3541,9 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        if (vmx->rmode.irq.pending)
                fixup_rmode_irq(vmx);
 
-       vmx_update_window_states(vcpu);
-
        asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
        vmx->launched = 1;
 
-       intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
-
-       /* We need to handle NMIs before interrupts are enabled */
-       if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR &&
-           (intr_info & INTR_INFO_VALID_MASK)) {
-               KVMTRACE_0D(NMI, vcpu, handler);
-               asm("int $2");
-       }
-
        vmx_complete_interrupts(vmx);
 }
 
@@ -3593,7 +3618,7 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
                if (alloc_apic_access_page(kvm) != 0)
                        goto free_vmcs;
 
-       if (vm_need_ept())
+       if (enable_ept)
                if (alloc_identity_pagetable(kvm) != 0)
                        goto free_vmcs;
 
@@ -3631,9 +3656,32 @@ static int get_ept_level(void)
        return VMX_EPT_DEFAULT_GAW + 1;
 }
 
-static int vmx_get_mt_mask_shift(void)
+static u64 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
 {
-       return VMX_EPT_MT_EPTE_SHIFT;
+       u64 ret;
+
+       /* For VT-d and EPT combination
+        * 1. MMIO: always map as UC
+        * 2. EPT with VT-d:
+        *   a. VT-d without snooping control feature: can't guarantee the
+        *      result, try to trust guest.
+        *   b. VT-d with snooping control feature: snooping control feature of
+        *      VT-d engine can guarantee the cache correctness. Just set it
+        *      to WB to keep consistent with host. So the same as item 3.
+        * 3. EPT without VT-d: always map as WB and set IGMT=1 to keep
+        *    consistent with host MTRR
+        */
+       if (is_mmio)
+               ret = MTRR_TYPE_UNCACHABLE << VMX_EPT_MT_EPTE_SHIFT;
+       else if (vcpu->kvm->arch.iommu_domain &&
+               !(vcpu->kvm->arch.iommu_flags & KVM_IOMMU_CACHE_COHERENCY))
+               ret = kvm_get_guest_memory_type(vcpu, gfn) <<
+                     VMX_EPT_MT_EPTE_SHIFT;
+       else
+               ret = (MTRR_TYPE_WRBACK << VMX_EPT_MT_EPTE_SHIFT)
+                       | VMX_EPT_IGMT_BIT;
+
+       return ret;
 }
 
 static struct kvm_x86_ops vmx_x86_ops = {
@@ -3644,7 +3692,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
        .check_processor_compatibility = vmx_check_processor_compat,
        .hardware_enable = hardware_enable,
        .hardware_disable = hardware_disable,
-       .cpu_has_accelerated_tpr = cpu_has_vmx_virtualize_apic_accesses,
+       .cpu_has_accelerated_tpr = report_flexpriority,
 
        .vcpu_create = vmx_create_vcpu,
        .vcpu_free = vmx_free_vcpu,
@@ -3678,78 +3726,82 @@ static struct kvm_x86_ops vmx_x86_ops = {
        .tlb_flush = vmx_flush_tlb,
 
        .run = vmx_vcpu_run,
-       .handle_exit = kvm_handle_exit,
+       .handle_exit = vmx_handle_exit,
        .skip_emulated_instruction = skip_emulated_instruction,
+       .set_interrupt_shadow = vmx_set_interrupt_shadow,
+       .get_interrupt_shadow = vmx_get_interrupt_shadow,
        .patch_hypercall = vmx_patch_hypercall,
-       .get_irq = vmx_get_irq,
        .set_irq = vmx_inject_irq,
+       .set_nmi = vmx_inject_nmi,
        .queue_exception = vmx_queue_exception,
-       .exception_injected = vmx_exception_injected,
-       .inject_pending_irq = vmx_intr_assist,
-       .inject_pending_vectors = do_interrupt_requests,
+       .interrupt_allowed = vmx_interrupt_allowed,
+       .nmi_allowed = vmx_nmi_allowed,
+       .enable_nmi_window = enable_nmi_window,
+       .enable_irq_window = enable_irq_window,
+       .update_cr8_intercept = update_cr8_intercept,
 
        .set_tss_addr = vmx_set_tss_addr,
        .get_tdp_level = get_ept_level,
-       .get_mt_mask_shift = vmx_get_mt_mask_shift,
+       .get_mt_mask = vmx_get_mt_mask,
 };
 
 static int __init vmx_init(void)
 {
-       void *va;
        int r;
 
-       vmx_io_bitmap_a = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+       vmx_io_bitmap_a = (unsigned long *)__get_free_page(GFP_KERNEL);
        if (!vmx_io_bitmap_a)
                return -ENOMEM;
 
-       vmx_io_bitmap_b = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+       vmx_io_bitmap_b = (unsigned long *)__get_free_page(GFP_KERNEL);
        if (!vmx_io_bitmap_b) {
                r = -ENOMEM;
                goto out;
        }
 
-       vmx_msr_bitmap = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
-       if (!vmx_msr_bitmap) {
+       vmx_msr_bitmap_legacy = (unsigned long *)__get_free_page(GFP_KERNEL);
+       if (!vmx_msr_bitmap_legacy) {
                r = -ENOMEM;
                goto out1;
        }
 
+       vmx_msr_bitmap_longmode = (unsigned long *)__get_free_page(GFP_KERNEL);
+       if (!vmx_msr_bitmap_longmode) {
+               r = -ENOMEM;
+               goto out2;
+       }
+
        /*
         * Allow direct access to the PC debug port (it is often used for I/O
         * delays, but the vmexits simply slow things down).
         */
-       va = kmap(vmx_io_bitmap_a);
-       memset(va, 0xff, PAGE_SIZE);
-       clear_bit(0x80, va);
-       kunmap(vmx_io_bitmap_a);
+       memset(vmx_io_bitmap_a, 0xff, PAGE_SIZE);
+       clear_bit(0x80, vmx_io_bitmap_a);
 
-       va = kmap(vmx_io_bitmap_b);
-       memset(va, 0xff, PAGE_SIZE);
-       kunmap(vmx_io_bitmap_b);
+       memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE);
 
-       va = kmap(vmx_msr_bitmap);
-       memset(va, 0xff, PAGE_SIZE);
-       kunmap(vmx_msr_bitmap);
+       memset(vmx_msr_bitmap_legacy, 0xff, PAGE_SIZE);
+       memset(vmx_msr_bitmap_longmode, 0xff, PAGE_SIZE);
 
        set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */
 
        r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE);
        if (r)
-               goto out2;
+               goto out3;
 
-       vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_FS_BASE);
-       vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_GS_BASE);
-       vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_CS);
-       vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_ESP);
-       vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_EIP);
+       vmx_disable_intercept_for_msr(MSR_FS_BASE, false);
+       vmx_disable_intercept_for_msr(MSR_GS_BASE, false);
+       vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true);
+       vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false);
+       vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
+       vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
 
-       if (vm_need_ept()) {
+       if (enable_ept) {
                bypass_guest_pf = 0;
                kvm_mmu_set_base_ptes(VMX_EPT_READABLE_MASK |
                        VMX_EPT_WRITABLE_MASK);
                kvm_mmu_set_mask_ptes(0ull, 0ull, 0ull, 0ull,
-                               VMX_EPT_EXECUTABLE_MASK,
-                               VMX_EPT_DEFAULT_MT << VMX_EPT_MT_EPTE_SHIFT);
+                               VMX_EPT_EXECUTABLE_MASK);
                kvm_enable_tdp();
        } else
                kvm_disable_tdp();
@@ -3761,20 +3813,23 @@ static int __init vmx_init(void)
 
        return 0;
 
+out3:
+       free_page((unsigned long)vmx_msr_bitmap_longmode);
 out2:
-       __free_page(vmx_msr_bitmap);
+       free_page((unsigned long)vmx_msr_bitmap_legacy);
 out1:
-       __free_page(vmx_io_bitmap_b);
+       free_page((unsigned long)vmx_io_bitmap_b);
 out:
-       __free_page(vmx_io_bitmap_a);
+       free_page((unsigned long)vmx_io_bitmap_a);
        return r;
 }
 
 static void __exit vmx_exit(void)
 {
-       __free_page(vmx_msr_bitmap);
-       __free_page(vmx_io_bitmap_b);
-       __free_page(vmx_io_bitmap_a);
+       free_page((unsigned long)vmx_msr_bitmap_legacy);
+       free_page((unsigned long)vmx_msr_bitmap_longmode);
+       free_page((unsigned long)vmx_io_bitmap_b);
+       free_page((unsigned long)vmx_io_bitmap_a);
 
        kvm_exit();
 }
index 3944e917e794fad77dc54d2afaedda47d6dcdca7..249540f985132f79922736a8dd49f8febeb71bdf 100644 (file)
@@ -91,7 +91,6 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "halt_wakeup", VCPU_STAT(halt_wakeup) },
        { "hypercalls", VCPU_STAT(hypercalls) },
        { "request_irq", VCPU_STAT(request_irq_exits) },
-       { "request_nmi", VCPU_STAT(request_nmi_exits) },
        { "irq_exits", VCPU_STAT(irq_exits) },
        { "host_state_reload", VCPU_STAT(host_state_reload) },
        { "efer_reload", VCPU_STAT(efer_reload) },
@@ -108,7 +107,6 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "mmu_recycled", VM_STAT(mmu_recycled) },
        { "mmu_cache_miss", VM_STAT(mmu_cache_miss) },
        { "mmu_unsync", VM_STAT(mmu_unsync) },
-       { "mmu_unsync_global", VM_STAT(mmu_unsync_global) },
        { "remote_tlb_flush", VM_STAT(remote_tlb_flush) },
        { "largepages", VM_STAT(lpages) },
        { NULL }
@@ -234,7 +232,8 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
                goto out;
        }
        for (i = 0; i < ARRAY_SIZE(pdpte); ++i) {
-               if ((pdpte[i] & 1) && (pdpte[i] & 0xfffffff0000001e6ull)) {
+               if (is_present_pte(pdpte[i]) &&
+                   (pdpte[i] & vcpu->arch.mmu.rsvd_bits_mask[0][2])) {
                        ret = 0;
                        goto out;
                }
@@ -321,7 +320,6 @@ void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
        kvm_x86_ops->set_cr0(vcpu, cr0);
        vcpu->arch.cr0 = cr0;
 
-       kvm_mmu_sync_global(vcpu);
        kvm_mmu_reset_context(vcpu);
        return;
 }
@@ -370,7 +368,6 @@ void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
        kvm_x86_ops->set_cr4(vcpu, cr4);
        vcpu->arch.cr4 = cr4;
        vcpu->arch.mmu.base_role.cr4_pge = (cr4 & X86_CR4_PGE) && !tdp_enabled;
-       kvm_mmu_sync_global(vcpu);
        kvm_mmu_reset_context(vcpu);
 }
 EXPORT_SYMBOL_GPL(kvm_set_cr4);
@@ -523,6 +520,9 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer)
        efer |= vcpu->arch.shadow_efer & EFER_LMA;
 
        vcpu->arch.shadow_efer = efer;
+
+       vcpu->arch.mmu.base_role.nxe = (efer & EFER_NX) && !tdp_enabled;
+       kvm_mmu_reset_context(vcpu);
 }
 
 void kvm_enable_efer_bits(u64 mask)
@@ -630,14 +630,17 @@ static void kvm_write_guest_time(struct kvm_vcpu *v)
        unsigned long flags;
        struct kvm_vcpu_arch *vcpu = &v->arch;
        void *shared_kaddr;
+       unsigned long this_tsc_khz;
 
        if ((!vcpu->time_page))
                return;
 
-       if (unlikely(vcpu->hv_clock_tsc_khz != __get_cpu_var(cpu_tsc_khz))) {
-               kvm_set_time_scale(__get_cpu_var(cpu_tsc_khz), &vcpu->hv_clock);
-               vcpu->hv_clock_tsc_khz = __get_cpu_var(cpu_tsc_khz);
+       this_tsc_khz = get_cpu_var(cpu_tsc_khz);
+       if (unlikely(vcpu->hv_clock_tsc_khz != this_tsc_khz)) {
+               kvm_set_time_scale(this_tsc_khz, &vcpu->hv_clock);
+               vcpu->hv_clock_tsc_khz = this_tsc_khz;
        }
+       put_cpu_var(cpu_tsc_khz);
 
        /* Keep irq disabled to prevent changes to the clock */
        local_irq_save(flags);
@@ -893,6 +896,8 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
        case MSR_IA32_LASTINTFROMIP:
        case MSR_IA32_LASTINTTOIP:
        case MSR_VM_HSAVE_PA:
+       case MSR_P6_EVNTSEL0:
+       case MSR_P6_EVNTSEL1:
                data = 0;
                break;
        case MSR_MTRRcap:
@@ -1024,6 +1029,7 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_SYNC_MMU:
        case KVM_CAP_REINJECT_CONTROL:
        case KVM_CAP_IRQ_INJECT_STATUS:
+       case KVM_CAP_ASSIGN_DEV_IRQ:
                r = 1;
                break;
        case KVM_CAP_COALESCED_MMIO:
@@ -1241,41 +1247,53 @@ static void do_cpuid_1_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        entry->flags = 0;
 }
 
+#define F(x) bit(X86_FEATURE_##x)
+
 static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                         u32 index, int *nent, int maxnent)
 {
-       const u32 kvm_supported_word0_x86_features = bit(X86_FEATURE_FPU) |
-               bit(X86_FEATURE_VME) | bit(X86_FEATURE_DE) |
-               bit(X86_FEATURE_PSE) | bit(X86_FEATURE_TSC) |
-               bit(X86_FEATURE_MSR) | bit(X86_FEATURE_PAE) |
-               bit(X86_FEATURE_CX8) | bit(X86_FEATURE_APIC) |
-               bit(X86_FEATURE_SEP) | bit(X86_FEATURE_PGE) |
-               bit(X86_FEATURE_CMOV) | bit(X86_FEATURE_PSE36) |
-               bit(X86_FEATURE_CLFLSH) | bit(X86_FEATURE_MMX) |
-               bit(X86_FEATURE_FXSR) | bit(X86_FEATURE_XMM) |
-               bit(X86_FEATURE_XMM2) | bit(X86_FEATURE_SELFSNOOP);
-       const u32 kvm_supported_word1_x86_features = bit(X86_FEATURE_FPU) |
-               bit(X86_FEATURE_VME) | bit(X86_FEATURE_DE) |
-               bit(X86_FEATURE_PSE) | bit(X86_FEATURE_TSC) |
-               bit(X86_FEATURE_MSR) | bit(X86_FEATURE_PAE) |
-               bit(X86_FEATURE_CX8) | bit(X86_FEATURE_APIC) |
-               bit(X86_FEATURE_PGE) |
-               bit(X86_FEATURE_CMOV) | bit(X86_FEATURE_PSE36) |
-               bit(X86_FEATURE_MMX) | bit(X86_FEATURE_FXSR) |
-               bit(X86_FEATURE_SYSCALL) |
-               (is_efer_nx() ? bit(X86_FEATURE_NX) : 0) |
+       unsigned f_nx = is_efer_nx() ? F(NX) : 0;
 #ifdef CONFIG_X86_64
-               bit(X86_FEATURE_LM) |
+       unsigned f_lm = F(LM);
+#else
+       unsigned f_lm = 0;
 #endif
-               bit(X86_FEATURE_FXSR_OPT) |
-               bit(X86_FEATURE_MMXEXT) |
-               bit(X86_FEATURE_3DNOWEXT) |
-               bit(X86_FEATURE_3DNOW);
-       const u32 kvm_supported_word3_x86_features =
-               bit(X86_FEATURE_XMM3) | bit(X86_FEATURE_CX16);
+
+       /* cpuid 1.edx */
+       const u32 kvm_supported_word0_x86_features =
+               F(FPU) | F(VME) | F(DE) | F(PSE) |
+               F(TSC) | F(MSR) | F(PAE) | F(MCE) |
+               F(CX8) | F(APIC) | 0 /* Reserved */ | F(SEP) |
+               F(MTRR) | F(PGE) | F(MCA) | F(CMOV) |
+               F(PAT) | F(PSE36) | 0 /* PSN */ | F(CLFLSH) |
+               0 /* Reserved, DS, ACPI */ | F(MMX) |
+               F(FXSR) | F(XMM) | F(XMM2) | F(SELFSNOOP) |
+               0 /* HTT, TM, Reserved, PBE */;
+       /* cpuid 0x80000001.edx */
+       const u32 kvm_supported_word1_x86_features =
+               F(FPU) | F(VME) | F(DE) | F(PSE) |
+               F(TSC) | F(MSR) | F(PAE) | F(MCE) |
+               F(CX8) | F(APIC) | 0 /* Reserved */ | F(SYSCALL) |
+               F(MTRR) | F(PGE) | F(MCA) | F(CMOV) |
+               F(PAT) | F(PSE36) | 0 /* Reserved */ |
+               f_nx | 0 /* Reserved */ | F(MMXEXT) | F(MMX) |
+               F(FXSR) | F(FXSR_OPT) | 0 /* GBPAGES */ | 0 /* RDTSCP */ |
+               0 /* Reserved */ | f_lm | F(3DNOWEXT) | F(3DNOW);
+       /* cpuid 1.ecx */
+       const u32 kvm_supported_word4_x86_features =
+               F(XMM3) | 0 /* Reserved, DTES64, MONITOR */ |
+               0 /* DS-CPL, VMX, SMX, EST */ |
+               0 /* TM2 */ | F(SSSE3) | 0 /* CNXT-ID */ | 0 /* Reserved */ |
+               0 /* Reserved */ | F(CX16) | 0 /* xTPR Update, PDCM */ |
+               0 /* Reserved, DCA */ | F(XMM4_1) |
+               F(XMM4_2) | 0 /* x2APIC */ | F(MOVBE) | F(POPCNT) |
+               0 /* Reserved, XSAVE, OSXSAVE */;
+       /* cpuid 0x80000001.ecx */
        const u32 kvm_supported_word6_x86_features =
-               bit(X86_FEATURE_LAHF_LM) | bit(X86_FEATURE_CMP_LEGACY) |
-               bit(X86_FEATURE_SVM);
+               F(LAHF_LM) | F(CMP_LEGACY) | F(SVM) | 0 /* ExtApicSpace */ |
+               F(CR8_LEGACY) | F(ABM) | F(SSE4A) | F(MISALIGNSSE) |
+               F(3DNOWPREFETCH) | 0 /* OSVW */ | 0 /* IBS */ | F(SSE5) |
+               0 /* SKINIT */ | 0 /* WDT */;
 
        /* all calls to cpuid_count() should be made on the same cpu */
        get_cpu();
@@ -1288,7 +1306,7 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                break;
        case 1:
                entry->edx &= kvm_supported_word0_x86_features;
-               entry->ecx &= kvm_supported_word3_x86_features;
+               entry->ecx &= kvm_supported_word4_x86_features;
                break;
        /* function 2 entries are STATEFUL. That is, repeated cpuid commands
         * may return different values. This forces us to get_cpu() before
@@ -1350,6 +1368,8 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        put_cpu();
 }
 
+#undef F
+
 static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
                                     struct kvm_cpuid_entry2 __user *entries)
 {
@@ -1421,8 +1441,7 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
                return -ENXIO;
        vcpu_load(vcpu);
 
-       set_bit(irq->irq, vcpu->arch.irq_pending);
-       set_bit(irq->irq / BITS_PER_LONG, &vcpu->arch.irq_summary);
+       kvm_queue_interrupt(vcpu, irq->irq, false);
 
        vcpu_put(vcpu);
 
@@ -1584,8 +1603,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                r = -EINVAL;
        }
 out:
-       if (lapic)
-               kfree(lapic);
+       kfree(lapic);
        return r;
 }
 
@@ -1606,10 +1624,12 @@ static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm,
                return -EINVAL;
 
        down_write(&kvm->slots_lock);
+       spin_lock(&kvm->mmu_lock);
 
        kvm_mmu_change_mmu_pages(kvm, kvm_nr_mmu_pages);
        kvm->arch.n_requested_mmu_pages = kvm_nr_mmu_pages;
 
+       spin_unlock(&kvm->mmu_lock);
        up_write(&kvm->slots_lock);
        return 0;
 }
@@ -1785,7 +1805,9 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 
        /* If nothing is dirty, don't bother messing with page tables. */
        if (is_dirty) {
+               spin_lock(&kvm->mmu_lock);
                kvm_mmu_slot_remove_write_access(kvm, log->slot);
+               spin_unlock(&kvm->mmu_lock);
                kvm_flush_remote_tlbs(kvm);
                memslot = &kvm->memslots[log->slot];
                n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
@@ -2360,7 +2382,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
                        u16 error_code,
                        int emulation_type)
 {
-       int r;
+       int r, shadow_mask;
        struct decode_cache *c;
 
        kvm_clear_exception_queue(vcpu);
@@ -2408,7 +2430,16 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
                }
        }
 
+       if (emulation_type & EMULTYPE_SKIP) {
+               kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.decode.eip);
+               return EMULATE_DONE;
+       }
+
        r = x86_emulate_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
+       shadow_mask = vcpu->arch.emulate_ctxt.interruptibility;
+
+       if (r == 0)
+               kvm_x86_ops->set_interrupt_shadow(vcpu, shadow_mask);
 
        if (vcpu->arch.pio.string)
                return EMULATE_DO_MMIO;
@@ -2761,7 +2792,7 @@ int kvm_arch_init(void *opaque)
        kvm_mmu_set_nonpresent_ptes(0ull, 0ull);
        kvm_mmu_set_base_ptes(PT_PRESENT_MASK);
        kvm_mmu_set_mask_ptes(PT_USER_MASK, PT_ACCESSED_MASK,
-                       PT_DIRTY_MASK, PT64_NX_MASK, 0, 0);
+                       PT_DIRTY_MASK, PT64_NX_MASK, 0);
 
        for_each_possible_cpu(cpu)
                per_cpu(cpu_tsc_khz, cpu) = tsc_khz;
@@ -3012,6 +3043,16 @@ struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
        return best;
 }
 
+int cpuid_maxphyaddr(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpuid_entry2 *best;
+
+       best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0);
+       if (best)
+               return best->eax & 0xff;
+       return 36;
+}
+
 void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
 {
        u32 function, index;
@@ -3048,10 +3089,9 @@ EXPORT_SYMBOL_GPL(kvm_emulate_cpuid);
 static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
                                          struct kvm_run *kvm_run)
 {
-       return (!vcpu->arch.irq_summary &&
+       return (!irqchip_in_kernel(vcpu->kvm) && !kvm_cpu_has_interrupt(vcpu) &&
                kvm_run->request_interrupt_window &&
-               vcpu->arch.interrupt_window_open &&
-               (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF));
+               kvm_arch_interrupt_allowed(vcpu));
 }
 
 static void post_kvm_run_save(struct kvm_vcpu *vcpu,
@@ -3064,8 +3104,9 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu,
                kvm_run->ready_for_interrupt_injection = 1;
        else
                kvm_run->ready_for_interrupt_injection =
-                                       (vcpu->arch.interrupt_window_open &&
-                                        vcpu->arch.irq_summary == 0);
+                       kvm_arch_interrupt_allowed(vcpu) &&
+                       !kvm_cpu_has_interrupt(vcpu) &&
+                       !kvm_event_needs_reinjection(vcpu);
 }
 
 static void vapic_enter(struct kvm_vcpu *vcpu)
@@ -3094,9 +3135,63 @@ static void vapic_exit(struct kvm_vcpu *vcpu)
        up_read(&vcpu->kvm->slots_lock);
 }
 
+static void update_cr8_intercept(struct kvm_vcpu *vcpu)
+{
+       int max_irr, tpr;
+
+       if (!kvm_x86_ops->update_cr8_intercept)
+               return;
+
+       if (!vcpu->arch.apic->vapic_addr)
+               max_irr = kvm_lapic_find_highest_irr(vcpu);
+       else
+               max_irr = -1;
+
+       if (max_irr != -1)
+               max_irr >>= 4;
+
+       tpr = kvm_lapic_get_cr8(vcpu);
+
+       kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr);
+}
+
+static void inject_pending_irq(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+               kvm_x86_ops->set_interrupt_shadow(vcpu, 0);
+
+       /* try to reinject previous events if any */
+       if (vcpu->arch.nmi_injected) {
+               kvm_x86_ops->set_nmi(vcpu);
+               return;
+       }
+
+       if (vcpu->arch.interrupt.pending) {
+               kvm_x86_ops->set_irq(vcpu);
+               return;
+       }
+
+       /* try to inject new event if pending */
+       if (vcpu->arch.nmi_pending) {
+               if (kvm_x86_ops->nmi_allowed(vcpu)) {
+                       vcpu->arch.nmi_pending = false;
+                       vcpu->arch.nmi_injected = true;
+                       kvm_x86_ops->set_nmi(vcpu);
+               }
+       } else if (kvm_cpu_has_interrupt(vcpu)) {
+               if (kvm_x86_ops->interrupt_allowed(vcpu)) {
+                       kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu),
+                                           false);
+                       kvm_x86_ops->set_irq(vcpu);
+               }
+       }
+}
+
 static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
        int r;
+       bool req_int_win = !irqchip_in_kernel(vcpu->kvm) &&
+               kvm_run->request_interrupt_window;
 
        if (vcpu->requests)
                if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
@@ -3128,9 +3223,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                }
        }
 
-       clear_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests);
-       kvm_inject_pending_timer_irqs(vcpu);
-
        preempt_disable();
 
        kvm_x86_ops->prepare_guest_switch(vcpu);
@@ -3138,6 +3230,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
        local_irq_disable();
 
+       clear_bit(KVM_REQ_KICK, &vcpu->requests);
+       smp_mb__after_clear_bit();
+
        if (vcpu->requests || need_resched() || signal_pending(current)) {
                local_irq_enable();
                preempt_enable();
@@ -3145,21 +3240,21 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                goto out;
        }
 
-       vcpu->guest_mode = 1;
-       /*
-        * Make sure that guest_mode assignment won't happen after
-        * testing the pending IRQ vector bitmap.
-        */
-       smp_wmb();
-
        if (vcpu->arch.exception.pending)
                __queue_exception(vcpu);
-       else if (irqchip_in_kernel(vcpu->kvm))
-               kvm_x86_ops->inject_pending_irq(vcpu);
        else
-               kvm_x86_ops->inject_pending_vectors(vcpu, kvm_run);
+               inject_pending_irq(vcpu, kvm_run);
 
-       kvm_lapic_sync_to_vapic(vcpu);
+       /* enable NMI/IRQ window open exits if needed */
+       if (vcpu->arch.nmi_pending)
+               kvm_x86_ops->enable_nmi_window(vcpu);
+       else if (kvm_cpu_has_interrupt(vcpu) || req_int_win)
+               kvm_x86_ops->enable_irq_window(vcpu);
+
+       if (kvm_lapic_enabled(vcpu)) {
+               update_cr8_intercept(vcpu);
+               kvm_lapic_sync_to_vapic(vcpu);
+       }
 
        up_read(&vcpu->kvm->slots_lock);
 
@@ -3193,7 +3288,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        set_debugreg(vcpu->arch.host_dr6, 6);
        set_debugreg(vcpu->arch.host_dr7, 7);
 
-       vcpu->guest_mode = 0;
+       set_bit(KVM_REQ_KICK, &vcpu->requests);
        local_irq_enable();
 
        ++vcpu->stat.exits;
@@ -3220,8 +3315,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                profile_hit(KVM_PROFILING, (void *)rip);
        }
 
-       if (vcpu->arch.exception.pending && kvm_x86_ops->exception_injected(vcpu))
-               vcpu->arch.exception.pending = false;
 
        kvm_lapic_sync_from_vapic(vcpu);
 
@@ -3230,6 +3323,7 @@ out:
        return r;
 }
 
+
 static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
        int r;
@@ -3256,29 +3350,42 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                        kvm_vcpu_block(vcpu);
                        down_read(&vcpu->kvm->slots_lock);
                        if (test_and_clear_bit(KVM_REQ_UNHALT, &vcpu->requests))
-                               if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED)
+                       {
+                               switch(vcpu->arch.mp_state) {
+                               case KVM_MP_STATE_HALTED:
                                        vcpu->arch.mp_state =
-                                                       KVM_MP_STATE_RUNNABLE;
-                       if (vcpu->arch.mp_state != KVM_MP_STATE_RUNNABLE)
-                               r = -EINTR;
+                                               KVM_MP_STATE_RUNNABLE;
+                               case KVM_MP_STATE_RUNNABLE:
+                                       break;
+                               case KVM_MP_STATE_SIPI_RECEIVED:
+                               default:
+                                       r = -EINTR;
+                                       break;
+                               }
+                       }
                }
 
-               if (r > 0) {
-                       if (dm_request_for_irq_injection(vcpu, kvm_run)) {
-                               r = -EINTR;
-                               kvm_run->exit_reason = KVM_EXIT_INTR;
-                               ++vcpu->stat.request_irq_exits;
-                       }
-                       if (signal_pending(current)) {
-                               r = -EINTR;
-                               kvm_run->exit_reason = KVM_EXIT_INTR;
-                               ++vcpu->stat.signal_exits;
-                       }
-                       if (need_resched()) {
-                               up_read(&vcpu->kvm->slots_lock);
-                               kvm_resched(vcpu);
-                               down_read(&vcpu->kvm->slots_lock);
-                       }
+               if (r <= 0)
+                       break;
+
+               clear_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests);
+               if (kvm_cpu_has_pending_timer(vcpu))
+                       kvm_inject_pending_timer_irqs(vcpu);
+
+               if (dm_request_for_irq_injection(vcpu, kvm_run)) {
+                       r = -EINTR;
+                       kvm_run->exit_reason = KVM_EXIT_INTR;
+                       ++vcpu->stat.request_irq_exits;
+               }
+               if (signal_pending(current)) {
+                       r = -EINTR;
+                       kvm_run->exit_reason = KVM_EXIT_INTR;
+                       ++vcpu->stat.signal_exits;
+               }
+               if (need_resched()) {
+                       up_read(&vcpu->kvm->slots_lock);
+                       kvm_resched(vcpu);
+                       down_read(&vcpu->kvm->slots_lock);
                }
        }
 
@@ -3442,7 +3549,6 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
                                  struct kvm_sregs *sregs)
 {
        struct descriptor_table dt;
-       int pending_vec;
 
        vcpu_load(vcpu);
 
@@ -3472,16 +3578,11 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
        sregs->efer = vcpu->arch.shadow_efer;
        sregs->apic_base = kvm_get_apic_base(vcpu);
 
-       if (irqchip_in_kernel(vcpu->kvm)) {
-               memset(sregs->interrupt_bitmap, 0,
-                      sizeof sregs->interrupt_bitmap);
-               pending_vec = kvm_x86_ops->get_irq(vcpu);
-               if (pending_vec >= 0)
-                       set_bit(pending_vec,
-                               (unsigned long *)sregs->interrupt_bitmap);
-       } else
-               memcpy(sregs->interrupt_bitmap, vcpu->arch.irq_pending,
-                      sizeof sregs->interrupt_bitmap);
+       memset(sregs->interrupt_bitmap, 0, sizeof sregs->interrupt_bitmap);
+
+       if (vcpu->arch.interrupt.pending && !vcpu->arch.interrupt.soft)
+               set_bit(vcpu->arch.interrupt.nr,
+                       (unsigned long *)sregs->interrupt_bitmap);
 
        vcpu_put(vcpu);
 
@@ -3688,7 +3789,6 @@ static void save_state_to_tss32(struct kvm_vcpu *vcpu,
        tss->fs = get_segment_selector(vcpu, VCPU_SREG_FS);
        tss->gs = get_segment_selector(vcpu, VCPU_SREG_GS);
        tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR);
-       tss->prev_task_link = get_segment_selector(vcpu, VCPU_SREG_TR);
 }
 
 static int load_state_from_tss32(struct kvm_vcpu *vcpu,
@@ -3785,8 +3885,8 @@ static int load_state_from_tss16(struct kvm_vcpu *vcpu,
 }
 
 static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
-                      u32 old_tss_base,
-                      struct desc_struct *nseg_desc)
+                             u16 old_tss_sel, u32 old_tss_base,
+                             struct desc_struct *nseg_desc)
 {
        struct tss_segment_16 tss_segment_16;
        int ret = 0;
@@ -3805,6 +3905,16 @@ static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
                           &tss_segment_16, sizeof tss_segment_16))
                goto out;
 
+       if (old_tss_sel != 0xffff) {
+               tss_segment_16.prev_task_link = old_tss_sel;
+
+               if (kvm_write_guest(vcpu->kvm,
+                                   get_tss_base_addr(vcpu, nseg_desc),
+                                   &tss_segment_16.prev_task_link,
+                                   sizeof tss_segment_16.prev_task_link))
+                       goto out;
+       }
+
        if (load_state_from_tss16(vcpu, &tss_segment_16))
                goto out;
 
@@ -3814,7 +3924,7 @@ out:
 }
 
 static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
-                      u32 old_tss_base,
+                      u16 old_tss_sel, u32 old_tss_base,
                       struct desc_struct *nseg_desc)
 {
        struct tss_segment_32 tss_segment_32;
@@ -3834,6 +3944,16 @@ static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
                           &tss_segment_32, sizeof tss_segment_32))
                goto out;
 
+       if (old_tss_sel != 0xffff) {
+               tss_segment_32.prev_task_link = old_tss_sel;
+
+               if (kvm_write_guest(vcpu->kvm,
+                                   get_tss_base_addr(vcpu, nseg_desc),
+                                   &tss_segment_32.prev_task_link,
+                                   sizeof tss_segment_32.prev_task_link))
+                       goto out;
+       }
+
        if (load_state_from_tss32(vcpu, &tss_segment_32))
                goto out;
 
@@ -3887,14 +4007,22 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
                kvm_x86_ops->set_rflags(vcpu, eflags & ~X86_EFLAGS_NT);
        }
 
-       kvm_x86_ops->skip_emulated_instruction(vcpu);
+       /* set back link to prev task only if NT bit is set in eflags
+          note that old_tss_sel is not used afetr this point */
+       if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE)
+               old_tss_sel = 0xffff;
+
+       /* set back link to prev task only if NT bit is set in eflags
+          note that old_tss_sel is not used afetr this point */
+       if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE)
+               old_tss_sel = 0xffff;
 
        if (nseg_desc.type & 8)
-               ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_base,
-                                        &nseg_desc);
+               ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_sel,
+                                        old_tss_base, &nseg_desc);
        else
-               ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_base,
-                                        &nseg_desc);
+               ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_sel,
+                                        old_tss_base, &nseg_desc);
 
        if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) {
                u32 eflags = kvm_x86_ops->get_rflags(vcpu);
@@ -3920,7 +4048,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
                                  struct kvm_sregs *sregs)
 {
        int mmu_reset_needed = 0;
-       int i, pending_vec, max_bits;
+       int pending_vec, max_bits;
        struct descriptor_table dt;
 
        vcpu_load(vcpu);
@@ -3934,7 +4062,13 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 
        vcpu->arch.cr2 = sregs->cr2;
        mmu_reset_needed |= vcpu->arch.cr3 != sregs->cr3;
-       vcpu->arch.cr3 = sregs->cr3;
+
+       down_read(&vcpu->kvm->slots_lock);
+       if (gfn_to_memslot(vcpu->kvm, sregs->cr3 >> PAGE_SHIFT))
+               vcpu->arch.cr3 = sregs->cr3;
+       else
+               set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
+       up_read(&vcpu->kvm->slots_lock);
 
        kvm_set_cr8(vcpu, sregs->cr8);
 
@@ -3956,25 +4090,14 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
        if (mmu_reset_needed)
                kvm_mmu_reset_context(vcpu);
 
-       if (!irqchip_in_kernel(vcpu->kvm)) {
-               memcpy(vcpu->arch.irq_pending, sregs->interrupt_bitmap,
-                      sizeof vcpu->arch.irq_pending);
-               vcpu->arch.irq_summary = 0;
-               for (i = 0; i < ARRAY_SIZE(vcpu->arch.irq_pending); ++i)
-                       if (vcpu->arch.irq_pending[i])
-                               __set_bit(i, &vcpu->arch.irq_summary);
-       } else {
-               max_bits = (sizeof sregs->interrupt_bitmap) << 3;
-               pending_vec = find_first_bit(
-                       (const unsigned long *)sregs->interrupt_bitmap,
-                       max_bits);
-               /* Only pending external irq is handled here */
-               if (pending_vec < max_bits) {
-                       kvm_x86_ops->set_irq(vcpu, pending_vec);
-                       pr_debug("Set back pending irq %d\n",
-                                pending_vec);
-               }
-               kvm_pic_clear_isr_ack(vcpu->kvm);
+       max_bits = (sizeof sregs->interrupt_bitmap) << 3;
+       pending_vec = find_first_bit(
+               (const unsigned long *)sregs->interrupt_bitmap, max_bits);
+       if (pending_vec < max_bits) {
+               kvm_queue_interrupt(vcpu, pending_vec, false);
+               pr_debug("Set back pending irq %d\n", pending_vec);
+               if (irqchip_in_kernel(vcpu->kvm))
+                       kvm_pic_clear_isr_ack(vcpu->kvm);
        }
 
        kvm_set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
@@ -4308,7 +4431,6 @@ struct  kvm *kvm_arch_create_vm(void)
                return ERR_PTR(-ENOMEM);
 
        INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
-       INIT_LIST_HEAD(&kvm->arch.oos_global_pages);
        INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);
 
        /* Reserve bit 0 of irq_sources_bitmap for userspace irq source */
@@ -4411,12 +4533,14 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
                }
        }
 
+       spin_lock(&kvm->mmu_lock);
        if (!kvm->arch.n_requested_mmu_pages) {
                unsigned int nr_mmu_pages = kvm_mmu_calculate_mmu_pages(kvm);
                kvm_mmu_change_mmu_pages(kvm, nr_mmu_pages);
        }
 
        kvm_mmu_slot_remove_write_access(kvm, mem->slot);
+       spin_unlock(&kvm->mmu_lock);
        kvm_flush_remote_tlbs(kvm);
 
        return 0;
@@ -4425,6 +4549,7 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
 void kvm_arch_flush_shadow(struct kvm *kvm)
 {
        kvm_mmu_zap_all(kvm);
+       kvm_reload_remote_mmus(kvm);
 }
 
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
@@ -4434,28 +4559,24 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
               || vcpu->arch.nmi_pending;
 }
 
-static void vcpu_kick_intr(void *info)
-{
-#ifdef DEBUG
-       struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info;
-       printk(KERN_DEBUG "vcpu_kick_intr %p \n", vcpu);
-#endif
-}
-
 void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
 {
-       int ipi_pcpu = vcpu->cpu;
-       int cpu = get_cpu();
+       int me;
+       int cpu = vcpu->cpu;
 
        if (waitqueue_active(&vcpu->wq)) {
                wake_up_interruptible(&vcpu->wq);
                ++vcpu->stat.halt_wakeup;
        }
-       /*
-        * We may be called synchronously with irqs disabled in guest mode,
-        * So need not to call smp_call_function_single() in that case.
-        */
-       if (vcpu->guest_mode && vcpu->cpu != cpu)
-               smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0);
+
+       me = get_cpu();
+       if (cpu != me && (unsigned)cpu < nr_cpu_ids && cpu_online(cpu))
+               if (!test_and_set_bit(KVM_REQ_KICK, &vcpu->requests))
+                       smp_send_reschedule(cpu);
        put_cpu();
 }
+
+int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
+{
+       return kvm_x86_ops->interrupt_allowed(vcpu);
+}
index 6a4be78a7384395d10f869287d552d59a5cb5060..4c8e10af78e88004acc1dd9df3c2fd2fa36cd85c 100644 (file)
@@ -8,9 +8,11 @@ static inline void kvm_clear_exception_queue(struct kvm_vcpu *vcpu)
        vcpu->arch.exception.pending = false;
 }
 
-static inline void kvm_queue_interrupt(struct kvm_vcpu *vcpu, u8 vector)
+static inline void kvm_queue_interrupt(struct kvm_vcpu *vcpu, u8 vector,
+       bool soft)
 {
        vcpu->arch.interrupt.pending = true;
+       vcpu->arch.interrupt.soft = soft;
        vcpu->arch.interrupt.nr = vector;
 }
 
@@ -19,4 +21,14 @@ static inline void kvm_clear_interrupt_queue(struct kvm_vcpu *vcpu)
        vcpu->arch.interrupt.pending = false;
 }
 
+static inline bool kvm_event_needs_reinjection(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.exception.pending || vcpu->arch.interrupt.pending ||
+               vcpu->arch.nmi_injected;
+}
+
+static inline bool kvm_exception_is_soft(unsigned int nr)
+{
+       return (nr == BP_VECTOR) || (nr == OF_VECTOR);
+}
 #endif
index ca91749d2083ff71a44b66f4253bda00dff7f4b3..c1b6c232e02b180287e7b0e91a41ddb34c699689 100644 (file)
 #define SrcImm      (5<<4)     /* Immediate operand. */
 #define SrcImmByte  (6<<4)     /* 8-bit sign-extended immediate operand. */
 #define SrcOne      (7<<4)     /* Implied '1' */
-#define SrcMask     (7<<4)
+#define SrcImmUByte (8<<4)      /* 8-bit unsigned immediate operand. */
+#define SrcMask     (0xf<<4)
 /* Generic ModRM decode. */
-#define ModRM       (1<<7)
+#define ModRM       (1<<8)
 /* Destination is only written; never read. */
-#define Mov         (1<<8)
-#define BitOp       (1<<9)
-#define MemAbs      (1<<10)      /* Memory operand is absolute displacement */
+#define Mov         (1<<9)
+#define BitOp       (1<<10)
+#define MemAbs      (1<<11)      /* Memory operand is absolute displacement */
 #define String      (1<<12)     /* String instruction (rep capable) */
 #define Stack       (1<<13)     /* Stack instruction (push/pop) */
 #define Group       (1<<14)     /* Bits 3:5 of modrm byte extend opcode */
@@ -76,6 +77,7 @@
 #define Src2CL      (1<<29)
 #define Src2ImmByte (2<<29)
 #define Src2One     (3<<29)
+#define Src2Imm16   (4<<29)
 #define Src2Mask    (7<<29)
 
 enum {
@@ -135,11 +137,11 @@ static u32 opcode_table[256] = {
        SrcNone  | ByteOp  | ImplicitOps, SrcNone  | ImplicitOps, /* insb, insw/insd */
        SrcNone  | ByteOp  | ImplicitOps, SrcNone  | ImplicitOps, /* outsb, outsw/outsd */
        /* 0x70 - 0x77 */
-       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+       SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
+       SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
        /* 0x78 - 0x7F */
-       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+       SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
+       SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
        /* 0x80 - 0x87 */
        Group | Group1_80, Group | Group1_81,
        Group | Group1_82, Group | Group1_83,
@@ -153,7 +155,8 @@ static u32 opcode_table[256] = {
        /* 0x90 - 0x97 */
        DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
        /* 0x98 - 0x9F */
-       0, 0, 0, 0, ImplicitOps | Stack, ImplicitOps | Stack, 0, 0,
+       0, 0, SrcImm | Src2Imm16, 0,
+       ImplicitOps | Stack, ImplicitOps | Stack, 0, 0,
        /* 0xA0 - 0xA7 */
        ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs,
        ByteOp | DstMem | SrcReg | Mov | MemAbs, DstMem | SrcReg | Mov | MemAbs,
@@ -178,7 +181,8 @@ static u32 opcode_table[256] = {
        0, ImplicitOps | Stack, 0, 0,
        ByteOp | DstMem | SrcImm | ModRM | Mov, DstMem | SrcImm | ModRM | Mov,
        /* 0xC8 - 0xCF */
-       0, 0, 0, ImplicitOps | Stack, 0, 0, 0, 0,
+       0, 0, 0, ImplicitOps | Stack,
+       ImplicitOps, SrcImmByte, ImplicitOps, ImplicitOps,
        /* 0xD0 - 0xD7 */
        ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
        ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
@@ -187,11 +191,11 @@ static u32 opcode_table[256] = {
        0, 0, 0, 0, 0, 0, 0, 0,
        /* 0xE0 - 0xE7 */
        0, 0, 0, 0,
-       SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
-       SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
+       ByteOp | SrcImmUByte, SrcImmUByte,
+       ByteOp | SrcImmUByte, SrcImmUByte,
        /* 0xE8 - 0xEF */
-       ImplicitOps | Stack, SrcImm | ImplicitOps,
-       ImplicitOps, SrcImmByte | ImplicitOps,
+       SrcImm | Stack, SrcImm | ImplicitOps,
+       SrcImm | Src2Imm16, SrcImmByte | ImplicitOps,
        SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
        SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
        /* 0xF0 - 0xF7 */
@@ -230,10 +234,8 @@ static u32 twobyte_table[256] = {
        /* 0x70 - 0x7F */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 0x80 - 0x8F */
-       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+       SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm,
+       SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm,
        /* 0x90 - 0x9F */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 0xA0 - 0xA7 */
@@ -1044,10 +1046,14 @@ done_prefixes:
                }
                break;
        case SrcImmByte:
+       case SrcImmUByte:
                c->src.type = OP_IMM;
                c->src.ptr = (unsigned long *)c->eip;
                c->src.bytes = 1;
-               c->src.val = insn_fetch(s8, 1, c->eip);
+               if ((c->d & SrcMask) == SrcImmByte)
+                       c->src.val = insn_fetch(s8, 1, c->eip);
+               else
+                       c->src.val = insn_fetch(u8, 1, c->eip);
                break;
        case SrcOne:
                c->src.bytes = 1;
@@ -1072,6 +1078,12 @@ done_prefixes:
                c->src2.bytes = 1;
                c->src2.val = insn_fetch(u8, 1, c->eip);
                break;
+       case Src2Imm16:
+               c->src2.type = OP_IMM;
+               c->src2.ptr = (unsigned long *)c->eip;
+               c->src2.bytes = 2;
+               c->src2.val = insn_fetch(u16, 2, c->eip);
+               break;
        case Src2One:
                c->src2.bytes = 1;
                c->src2.val = 1;
@@ -1349,6 +1361,20 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt,
        return 0;
 }
 
+void toggle_interruptibility(struct x86_emulate_ctxt *ctxt, u32 mask)
+{
+       u32 int_shadow = kvm_x86_ops->get_interrupt_shadow(ctxt->vcpu, mask);
+       /*
+        * an sti; sti; sequence only disable interrupts for the first
+        * instruction. So, if the last instruction, be it emulated or
+        * not, left the system with the INT_STI flag enabled, it
+        * means that the last instruction is an sti. We should not
+        * leave the flag on in this case. The same goes for mov ss
+        */
+       if (!(int_shadow & mask))
+               ctxt->interruptibility = mask;
+}
+
 int
 x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
 {
@@ -1360,6 +1386,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
        int io_dir_in;
        int rc = 0;
 
+       ctxt->interruptibility = 0;
+
        /* Shadow copy of register state. Committed on successful emulation.
         * NOTE: we can copy them from vcpu as x86_decode_insn() doesn't
         * modify them.
@@ -1531,13 +1559,10 @@ special_insn:
                        return -1;
                }
                return 0;
-       case 0x70 ... 0x7f: /* jcc (short) */ {
-               int rel = insn_fetch(s8, 1, c->eip);
-
+       case 0x70 ... 0x7f: /* jcc (short) */
                if (test_cc(c->b, ctxt->eflags))
-                       jmp_rel(c, rel);
+                       jmp_rel(c, c->src.val);
                break;
-       }
        case 0x80 ... 0x83:     /* Grp1 */
                switch (c->modrm_reg) {
                case 0:
@@ -1609,6 +1634,9 @@ special_insn:
                int err;
 
                sel = c->src.val;
+               if (c->modrm_reg == VCPU_SREG_SS)
+                       toggle_interruptibility(ctxt, X86_SHADOW_INT_MOV_SS);
+
                if (c->modrm_reg <= 5) {
                        type_bits = (c->modrm_reg == 1) ? 9 : 1;
                        err = kvm_load_segment_descriptor(ctxt->vcpu, sel,
@@ -1769,59 +1797,32 @@ special_insn:
                break;
        case 0xe4:      /* inb */
        case 0xe5:      /* in */
-               port = insn_fetch(u8, 1, c->eip);
+               port = c->src.val;
                io_dir_in = 1;
                goto do_io;
        case 0xe6: /* outb */
        case 0xe7: /* out */
-               port = insn_fetch(u8, 1, c->eip);
+               port = c->src.val;
                io_dir_in = 0;
                goto do_io;
        case 0xe8: /* call (near) */ {
-               long int rel;
-               switch (c->op_bytes) {
-               case 2:
-                       rel = insn_fetch(s16, 2, c->eip);
-                       break;
-               case 4:
-                       rel = insn_fetch(s32, 4, c->eip);
-                       break;
-               default:
-                       DPRINTF("Call: Invalid op_bytes\n");
-                       goto cannot_emulate;
-               }
+               long int rel = c->src.val;
                c->src.val = (unsigned long) c->eip;
                jmp_rel(c, rel);
-               c->op_bytes = c->ad_bytes;
                emulate_push(ctxt);
                break;
        }
        case 0xe9: /* jmp rel */
                goto jmp;
-       case 0xea: /* jmp far */ {
-               uint32_t eip;
-               uint16_t sel;
-
-               switch (c->op_bytes) {
-               case 2:
-                       eip = insn_fetch(u16, 2, c->eip);
-                       break;
-               case 4:
-                       eip = insn_fetch(u32, 4, c->eip);
-                       break;
-               default:
-                       DPRINTF("jmp far: Invalid op_bytes\n");
-                       goto cannot_emulate;
-               }
-               sel = insn_fetch(u16, 2, c->eip);
-               if (kvm_load_segment_descriptor(ctxt->vcpu, sel, 9, VCPU_SREG_CS) < 0) {
+       case 0xea: /* jmp far */
+               if (kvm_load_segment_descriptor(ctxt->vcpu, c->src2.val, 9,
+                                       VCPU_SREG_CS) < 0) {
                        DPRINTF("jmp far: Failed to load CS descriptor\n");
                        goto cannot_emulate;
                }
 
-               c->eip = eip;
+               c->eip = c->src.val;
                break;
-       }
        case 0xeb:
              jmp:              /* jmp rel short */
                jmp_rel(c, c->src.val);
@@ -1865,6 +1866,7 @@ special_insn:
                c->dst.type = OP_NONE;  /* Disable writeback. */
                break;
        case 0xfb: /* sti */
+               toggle_interruptibility(ctxt, X86_SHADOW_INT_STI);
                ctxt->eflags |= X86_EFLAGS_IF;
                c->dst.type = OP_NONE;  /* Disable writeback. */
                break;
@@ -2039,28 +2041,11 @@ twobyte_insn:
                if (!test_cc(c->b, ctxt->eflags))
                        c->dst.type = OP_NONE; /* no writeback */
                break;
-       case 0x80 ... 0x8f: /* jnz rel, etc*/ {
-               long int rel;
-
-               switch (c->op_bytes) {
-               case 2:
-                       rel = insn_fetch(s16, 2, c->eip);
-                       break;
-               case 4:
-                       rel = insn_fetch(s32, 4, c->eip);
-                       break;
-               case 8:
-                       rel = insn_fetch(s64, 8, c->eip);
-                       break;
-               default:
-                       DPRINTF("jnz: Invalid op_bytes\n");
-                       goto cannot_emulate;
-               }
+       case 0x80 ... 0x8f: /* jnz rel, etc*/
                if (test_cc(c->b, ctxt->eflags))
-                       jmp_rel(c, rel);
+                       jmp_rel(c, c->src.val);
                c->dst.type = OP_NONE;
                break;
-       }
        case 0xa3:
              bt:               /* bt */
                c->dst.type = OP_NONE;
index 33a93b41739612cafe1fe3d918c39a3915f86a78..4e0c265593958fcb70a8588d942a27a7d0ac3da6 100644 (file)
@@ -167,10 +167,16 @@ static void lazy_hcall3(unsigned long call,
 
 /* When lazy mode is turned off reset the per-cpu lazy mode variable and then
  * issue the do-nothing hypercall to flush any stored calls. */
-static void lguest_leave_lazy_mode(void)
+static void lguest_leave_lazy_mmu_mode(void)
 {
-       paravirt_leave_lazy(paravirt_get_lazy_mode());
        kvm_hypercall0(LHCALL_FLUSH_ASYNC);
+       paravirt_leave_lazy_mmu();
+}
+
+static void lguest_end_context_switch(struct task_struct *next)
+{
+       kvm_hypercall0(LHCALL_FLUSH_ASYNC);
+       paravirt_end_context_switch(next);
 }
 
 /*G:033
@@ -637,7 +643,7 @@ static void __init lguest_init_IRQ(void)
 
 void lguest_setup_irq(unsigned int irq)
 {
-       irq_to_desc_alloc_cpu(irq, 0);
+       irq_to_desc_alloc_node(irq, 0);
        set_irq_chip_and_handler_name(irq, &lguest_irq_controller,
                                      handle_level_irq, "level");
 }
@@ -1054,8 +1060,8 @@ __init void lguest_init(void)
        pv_cpu_ops.write_gdt_entry = lguest_write_gdt_entry;
        pv_cpu_ops.write_idt_entry = lguest_write_idt_entry;
        pv_cpu_ops.wbinvd = lguest_wbinvd;
-       pv_cpu_ops.lazy_mode.enter = paravirt_enter_lazy_cpu;
-       pv_cpu_ops.lazy_mode.leave = lguest_leave_lazy_mode;
+       pv_cpu_ops.start_context_switch = paravirt_start_context_switch;
+       pv_cpu_ops.end_context_switch = lguest_end_context_switch;
 
        /* pagetable management */
        pv_mmu_ops.write_cr3 = lguest_write_cr3;
@@ -1068,7 +1074,7 @@ __init void lguest_init(void)
        pv_mmu_ops.read_cr2 = lguest_read_cr2;
        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.lazy_mode.leave = lguest_leave_lazy_mmu_mode;
        pv_mmu_ops.pte_update = lguest_pte_update;
        pv_mmu_ops.pte_update_defer = lguest_pte_update;
 
index 55e11aa6d66cc51a75a7d6b04b3e921abf0a56ae..f9d35632666b06bb0b9bf072176777dbd94c39cc 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for x86 specific library files.
 #
 
-obj-$(CONFIG_SMP) := msr-on-cpu.o
+obj-$(CONFIG_SMP) := msr.o
 
 lib-y := delay.o
 lib-y += thunk_$(BITS).o
diff --git a/arch/x86/lib/msr-on-cpu.c b/arch/x86/lib/msr-on-cpu.c
deleted file mode 100644 (file)
index 321cf72..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-#include <linux/module.h>
-#include <linux/preempt.h>
-#include <linux/smp.h>
-#include <asm/msr.h>
-
-struct msr_info {
-       u32 msr_no;
-       u32 l, h;
-       int err;
-};
-
-static void __rdmsr_on_cpu(void *info)
-{
-       struct msr_info *rv = info;
-
-       rdmsr(rv->msr_no, rv->l, rv->h);
-}
-
-static void __wrmsr_on_cpu(void *info)
-{
-       struct msr_info *rv = info;
-
-       wrmsr(rv->msr_no, rv->l, rv->h);
-}
-
-int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
-{
-       int err;
-       struct msr_info rv;
-
-       rv.msr_no = msr_no;
-       err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1);
-       *l = rv.l;
-       *h = rv.h;
-
-       return err;
-}
-
-int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
-{
-       int err;
-       struct msr_info rv;
-
-       rv.msr_no = msr_no;
-       rv.l = l;
-       rv.h = h;
-       err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1);
-
-       return err;
-}
-
-/* These "safe" variants are slower and should be used when the target MSR
-   may not actually exist. */
-static void __rdmsr_safe_on_cpu(void *info)
-{
-       struct msr_info *rv = info;
-
-       rv->err = rdmsr_safe(rv->msr_no, &rv->l, &rv->h);
-}
-
-static void __wrmsr_safe_on_cpu(void *info)
-{
-       struct msr_info *rv = info;
-
-       rv->err = wrmsr_safe(rv->msr_no, rv->l, rv->h);
-}
-
-int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
-{
-       int err;
-       struct msr_info rv;
-
-       rv.msr_no = msr_no;
-       err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1);
-       *l = rv.l;
-       *h = rv.h;
-
-       return err ? err : rv.err;
-}
-
-int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
-{
-       int err;
-       struct msr_info rv;
-
-       rv.msr_no = msr_no;
-       rv.l = l;
-       rv.h = h;
-       err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1);
-
-       return err ? err : rv.err;
-}
-
-EXPORT_SYMBOL(rdmsr_on_cpu);
-EXPORT_SYMBOL(wrmsr_on_cpu);
-EXPORT_SYMBOL(rdmsr_safe_on_cpu);
-EXPORT_SYMBOL(wrmsr_safe_on_cpu);
diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c
new file mode 100644 (file)
index 0000000..1440b9c
--- /dev/null
@@ -0,0 +1,183 @@
+#include <linux/module.h>
+#include <linux/preempt.h>
+#include <linux/smp.h>
+#include <asm/msr.h>
+
+struct msr_info {
+       u32 msr_no;
+       struct msr reg;
+       struct msr *msrs;
+       int off;
+       int err;
+};
+
+static void __rdmsr_on_cpu(void *info)
+{
+       struct msr_info *rv = info;
+       struct msr *reg;
+       int this_cpu = raw_smp_processor_id();
+
+       if (rv->msrs)
+               reg = &rv->msrs[this_cpu - rv->off];
+       else
+               reg = &rv->reg;
+
+       rdmsr(rv->msr_no, reg->l, reg->h);
+}
+
+static void __wrmsr_on_cpu(void *info)
+{
+       struct msr_info *rv = info;
+       struct msr *reg;
+       int this_cpu = raw_smp_processor_id();
+
+       if (rv->msrs)
+               reg = &rv->msrs[this_cpu - rv->off];
+       else
+               reg = &rv->reg;
+
+       wrmsr(rv->msr_no, reg->l, reg->h);
+}
+
+int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
+{
+       int err;
+       struct msr_info rv;
+
+       memset(&rv, 0, sizeof(rv));
+
+       rv.msr_no = msr_no;
+       err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1);
+       *l = rv.reg.l;
+       *h = rv.reg.h;
+
+       return err;
+}
+EXPORT_SYMBOL(rdmsr_on_cpu);
+
+int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
+{
+       int err;
+       struct msr_info rv;
+
+       memset(&rv, 0, sizeof(rv));
+
+       rv.msr_no = msr_no;
+       rv.reg.l = l;
+       rv.reg.h = h;
+       err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1);
+
+       return err;
+}
+EXPORT_SYMBOL(wrmsr_on_cpu);
+
+/* rdmsr on a bunch of CPUs
+ *
+ * @mask:       which CPUs
+ * @msr_no:     which MSR
+ * @msrs:       array of MSR values
+ *
+ */
+void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)
+{
+       struct msr_info rv;
+       int this_cpu;
+
+       memset(&rv, 0, sizeof(rv));
+
+       rv.off    = cpumask_first(mask);
+       rv.msrs   = msrs;
+       rv.msr_no = msr_no;
+
+       preempt_disable();
+       /*
+        * FIXME: handle the CPU we're executing on separately for now until
+        * smp_call_function_many has been fixed to not skip it.
+        */
+       this_cpu = raw_smp_processor_id();
+       smp_call_function_single(this_cpu, __rdmsr_on_cpu, &rv, 1);
+
+       smp_call_function_many(mask, __rdmsr_on_cpu, &rv, 1);
+       preempt_enable();
+}
+EXPORT_SYMBOL(rdmsr_on_cpus);
+
+/*
+ * wrmsr on a bunch of CPUs
+ *
+ * @mask:       which CPUs
+ * @msr_no:     which MSR
+ * @msrs:       array of MSR values
+ *
+ */
+void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)
+{
+       struct msr_info rv;
+       int this_cpu;
+
+       memset(&rv, 0, sizeof(rv));
+
+       rv.off    = cpumask_first(mask);
+       rv.msrs   = msrs;
+       rv.msr_no = msr_no;
+
+       preempt_disable();
+       /*
+        * FIXME: handle the CPU we're executing on separately for now until
+        * smp_call_function_many has been fixed to not skip it.
+        */
+       this_cpu = raw_smp_processor_id();
+       smp_call_function_single(this_cpu, __wrmsr_on_cpu, &rv, 1);
+
+       smp_call_function_many(mask, __wrmsr_on_cpu, &rv, 1);
+       preempt_enable();
+}
+EXPORT_SYMBOL(wrmsr_on_cpus);
+
+/* These "safe" variants are slower and should be used when the target MSR
+   may not actually exist. */
+static void __rdmsr_safe_on_cpu(void *info)
+{
+       struct msr_info *rv = info;
+
+       rv->err = rdmsr_safe(rv->msr_no, &rv->reg.l, &rv->reg.h);
+}
+
+static void __wrmsr_safe_on_cpu(void *info)
+{
+       struct msr_info *rv = info;
+
+       rv->err = wrmsr_safe(rv->msr_no, rv->reg.l, rv->reg.h);
+}
+
+int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
+{
+       int err;
+       struct msr_info rv;
+
+       memset(&rv, 0, sizeof(rv));
+
+       rv.msr_no = msr_no;
+       err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1);
+       *l = rv.reg.l;
+       *h = rv.reg.h;
+
+       return err ? err : rv.err;
+}
+EXPORT_SYMBOL(rdmsr_safe_on_cpu);
+
+int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
+{
+       int err;
+       struct msr_info rv;
+
+       memset(&rv, 0, sizeof(rv));
+
+       rv.msr_no = msr_no;
+       rv.reg.l = l;
+       rv.reg.h = h;
+       err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1);
+
+       return err ? err : rv.err;
+}
+EXPORT_SYMBOL(wrmsr_safe_on_cpu);
index e7277cbcfb40ee1ea455fb63c4c6665656724013..a725b7f760ae4ba860e93b9af99b40931621430b 100644 (file)
@@ -161,13 +161,14 @@ static void note_page(struct seq_file *m, struct pg_state *st,
                   st->current_address >= st->marker[1].start_address) {
                const char *unit = units;
                unsigned long delta;
+               int width = sizeof(unsigned long) * 2;
 
                /*
                 * Now print the actual finished series
                 */
-               seq_printf(m, "0x%p-0x%p   ",
-                          (void *)st->start_address,
-                          (void *)st->current_address);
+               seq_printf(m, "0x%0*lx-0x%0*lx   ",
+                          width, st->start_address,
+                          width, st->current_address);
 
                delta = (st->current_address - st->start_address) >> 10;
                while (!(delta & 1023) && unit[1]) {
index a03b7279efa018850def9042339fec4af4249042..5ec7ae366615458eb18306a8cbd5987c6c06f17c 100644 (file)
@@ -3,40 +3,16 @@
  *  Copyright (C) 2001, 2002 Andi Kleen, SuSE Labs.
  *  Copyright (C) 2008-2009, Red Hat Inc., Ingo Molnar
  */
-#include <linux/interrupt.h>
-#include <linux/mmiotrace.h>
-#include <linux/bootmem.h>
-#include <linux/compiler.h>
-#include <linux/highmem.h>
-#include <linux/kprobes.h>
-#include <linux/uaccess.h>
-#include <linux/vmalloc.h>
-#include <linux/vt_kern.h>
-#include <linux/signal.h>
-#include <linux/kernel.h>
-#include <linux/ptrace.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/kdebug.h>
-#include <linux/errno.h>
-#include <linux/magic.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/mman.h>
-#include <linux/tty.h>
-#include <linux/smp.h>
-#include <linux/mm.h>
-
-#include <asm-generic/sections.h>
-
-#include <asm/tlbflush.h>
-#include <asm/pgalloc.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/proto.h>
-#include <asm/traps.h>
-#include <asm/desc.h>
+#include <linux/magic.h>               /* STACK_END_MAGIC              */
+#include <linux/sched.h>               /* test_thread_flag(), ...      */
+#include <linux/kdebug.h>              /* oops_begin/end, ...          */
+#include <linux/module.h>              /* search_exception_table       */
+#include <linux/bootmem.h>             /* max_low_pfn                  */
+#include <linux/kprobes.h>             /* __kprobes, ...               */
+#include <linux/mmiotrace.h>           /* kmmio_handler, ...           */
+
+#include <asm/traps.h>                 /* dotraplinkage, ...           */
+#include <asm/pgalloc.h>               /* pgd_*(), ...                 */
 
 /*
  * Page fault error code bits:
@@ -225,12 +201,10 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
        if (!pmd_present(*pmd_k))
                return NULL;
 
-       if (!pmd_present(*pmd)) {
+       if (!pmd_present(*pmd))
                set_pmd(pmd, *pmd_k);
-               arch_flush_lazy_mmu_mode();
-       } else {
+       else
                BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
-       }
 
        return pmd_k;
 }
@@ -538,8 +512,6 @@ bad:
 static int is_errata93(struct pt_regs *regs, unsigned long address)
 {
 #ifdef CONFIG_X86_64
-       static int once;
-
        if (address != regs->ip)
                return 0;
 
@@ -549,10 +521,7 @@ static int is_errata93(struct pt_regs *regs, unsigned long address)
        address |= 0xffffffffUL << 32;
        if ((address >= (u64)_stext && address <= (u64)_etext) ||
            (address >= MODULES_VADDR && address <= MODULES_END)) {
-               if (!once) {
-                       printk(errata93_warning);
-                       once = 1;
-               }
+               printk_once(errata93_warning);
                regs->ip = address;
                return 1;
        }
index 8126e8d1a2a4a789509cb49af563b6cbb76395ae..58f621e8191955c2e02016df1d8e99bec8e1ed8f 100644 (file)
@@ -44,7 +44,6 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
        BUG_ON(!pte_none(*(kmap_pte-idx)));
        set_pte(kmap_pte-idx, mk_pte(page, prot));
-       arch_flush_lazy_mmu_mode();
 
        return (void *)vaddr;
 }
@@ -74,7 +73,6 @@ void kunmap_atomic(void *kvaddr, enum km_type type)
 #endif
        }
 
-       arch_flush_lazy_mmu_mode();
        pagefault_enable();
 }
 
index ae4f7b5d71040566f7b30af16e6c00f20c82c098..34c1bfb64f1ca07d80838f363b514caf07acf4db 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/initrd.h>
 #include <linux/ioport.h>
 #include <linux/swap.h>
 
@@ -10,6 +11,9 @@
 #include <asm/setup.h>
 #include <asm/system.h>
 #include <asm/tlbflush.h>
+#include <asm/tlb.h>
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
 unsigned long __initdata e820_table_start;
 unsigned long __meminitdata e820_table_end;
@@ -23,6 +27,69 @@ int direct_gbpages
 #endif
 ;
 
+int nx_enabled;
+
+#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
+static int disable_nx __cpuinitdata;
+
+/*
+ * noexec = on|off
+ *
+ * Control non-executable mappings for processes.
+ *
+ * on      Enable
+ * off     Disable
+ */
+static int __init noexec_setup(char *str)
+{
+       if (!str)
+               return -EINVAL;
+       if (!strncmp(str, "on", 2)) {
+               __supported_pte_mask |= _PAGE_NX;
+               disable_nx = 0;
+       } else if (!strncmp(str, "off", 3)) {
+               disable_nx = 1;
+               __supported_pte_mask &= ~_PAGE_NX;
+       }
+       return 0;
+}
+early_param("noexec", noexec_setup);
+#endif
+
+#ifdef CONFIG_X86_PAE
+static void __init set_nx(void)
+{
+       unsigned int v[4], l, h;
+
+       if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) {
+               cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]);
+
+               if ((v[3] & (1 << 20)) && !disable_nx) {
+                       rdmsr(MSR_EFER, l, h);
+                       l |= EFER_NX;
+                       wrmsr(MSR_EFER, l, h);
+                       nx_enabled = 1;
+                       __supported_pte_mask |= _PAGE_NX;
+               }
+       }
+}
+#else
+static inline void set_nx(void)
+{
+}
+#endif
+
+#ifdef CONFIG_X86_64
+void __cpuinit check_efer(void)
+{
+       unsigned long efer;
+
+       rdmsrl(MSR_EFER, efer);
+       if (!(efer & EFER_NX) || disable_nx)
+               __supported_pte_mask &= ~_PAGE_NX;
+}
+#endif
+
 static void __init find_early_table_space(unsigned long end, int use_pse,
                                          int use_gbpages)
 {
@@ -66,12 +133,11 @@ static void __init find_early_table_space(unsigned long end, int use_pse,
         */
 #ifdef CONFIG_X86_32
        start = 0x7000;
-       e820_table_start = find_e820_area(start, max_pfn_mapped<<PAGE_SHIFT,
-                                       tables, PAGE_SIZE);
-#else /* CONFIG_X86_64 */
+#else
        start = 0x8000;
-       e820_table_start = find_e820_area(start, end, tables, PAGE_SIZE);
 #endif
+       e820_table_start = find_e820_area(start, max_pfn_mapped<<PAGE_SHIFT,
+                                       tables, PAGE_SIZE);
        if (e820_table_start == -1UL)
                panic("Cannot find space for the kernel page tables");
 
@@ -159,12 +225,9 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
        use_gbpages = direct_gbpages;
 #endif
 
-#ifdef CONFIG_X86_32
-#ifdef CONFIG_X86_PAE
        set_nx();
        if (nx_enabled)
                printk(KERN_INFO "NX (Execute Disable) protection: active\n");
-#endif
 
        /* Enable PSE if available */
        if (cpu_has_pse)
@@ -175,7 +238,6 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
                set_in_cr4(X86_CR4_PGE);
                __supported_pte_mask |= _PAGE_GLOBAL;
        }
-#endif
 
        if (use_gbpages)
                page_size_mask |= 1 << PG_LEVEL_1G;
index 749559ed80f5d99e1771826155ac8b27e1f2a3f2..949708d7a481ec10e9591faba7466b3e1a75f57d 100644 (file)
 #include <asm/paravirt.h>
 #include <asm/setup.h>
 #include <asm/cacheflush.h>
+#include <asm/page_types.h>
 #include <asm/init.h>
 
-unsigned long max_low_pfn_mapped;
-unsigned long max_pfn_mapped;
-
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 unsigned long highstart_pfn, highend_pfn;
 
 static noinline int do_test_wp_bit(void);
@@ -587,61 +584,9 @@ void zap_low_mappings(void)
        flush_tlb_all();
 }
 
-int nx_enabled;
-
 pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP);
 EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
-#ifdef CONFIG_X86_PAE
-
-static int disable_nx __initdata;
-
-/*
- * noexec = on|off
- *
- * Control non executable mappings.
- *
- * on      Enable
- * off     Disable
- */
-static int __init noexec_setup(char *str)
-{
-       if (!str || !strcmp(str, "on")) {
-               if (cpu_has_nx) {
-                       __supported_pte_mask |= _PAGE_NX;
-                       disable_nx = 0;
-               }
-       } else {
-               if (!strcmp(str, "off")) {
-                       disable_nx = 1;
-                       __supported_pte_mask &= ~_PAGE_NX;
-               } else {
-                       return -EINVAL;
-               }
-       }
-
-       return 0;
-}
-early_param("noexec", noexec_setup);
-
-void __init set_nx(void)
-{
-       unsigned int v[4], l, h;
-
-       if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) {
-               cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]);
-
-               if ((v[3] & (1 << 20)) && !disable_nx) {
-                       rdmsr(MSR_EFER, l, h);
-                       l |= EFER_NX;
-                       wrmsr(MSR_EFER, l, h);
-                       nx_enabled = 1;
-                       __supported_pte_mask |= _PAGE_NX;
-               }
-       }
-}
-#endif
-
 /* user-defined highmem size */
 static unsigned int highmem_pages = -1;
 
@@ -761,15 +706,15 @@ void __init initmem_init(unsigned long start_pfn,
        highstart_pfn = highend_pfn = max_pfn;
        if (max_pfn > max_low_pfn)
                highstart_pfn = max_low_pfn;
-       memory_present(0, 0, highend_pfn);
        e820_register_active_regions(0, 0, highend_pfn);
+       sparse_memory_present_with_active_regions(0);
        printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
                pages_to_mb(highend_pfn - highstart_pfn));
        num_physpages = highend_pfn;
        high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
 #else
-       memory_present(0, 0, max_low_pfn);
        e820_register_active_regions(0, 0, max_low_pfn);
+       sparse_memory_present_with_active_regions(0);
        num_physpages = max_low_pfn;
        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
 #endif
index 1753e8020df6ec8aa3eefea7342386224e595f2c..52bb9519bb86b4ec778d613939ea658adb1052a6 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/init.h>
 
-/*
- * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries.
- * The direct mapping extends to max_pfn_mapped, so that we can directly access
- * apertures, ACPI and other tables without having to play with fixmaps.
- */
-unsigned long max_low_pfn_mapped;
-unsigned long max_pfn_mapped;
-
 static unsigned long dma_reserve __initdata;
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 static int __init parse_direct_gbpages_off(char *arg)
 {
        direct_gbpages = 0;
@@ -85,39 +75,6 @@ early_param("gbpages", parse_direct_gbpages_on);
 pteval_t __supported_pte_mask __read_mostly = ~_PAGE_IOMAP;
 EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
-static int disable_nx __cpuinitdata;
-
-/*
- * noexec=on|off
- * Control non-executable mappings for 64-bit processes.
- *
- * on  Enable (default)
- * off Disable
- */
-static int __init nonx_setup(char *str)
-{
-       if (!str)
-               return -EINVAL;
-       if (!strncmp(str, "on", 2)) {
-               __supported_pte_mask |= _PAGE_NX;
-               disable_nx = 0;
-       } else if (!strncmp(str, "off", 3)) {
-               disable_nx = 1;
-               __supported_pte_mask &= ~_PAGE_NX;
-       }
-       return 0;
-}
-early_param("noexec", nonx_setup);
-
-void __cpuinit check_efer(void)
-{
-       unsigned long efer;
-
-       rdmsrl(MSR_EFER, efer);
-       if (!(efer & EFER_NX) || disable_nx)
-               __supported_pte_mask &= ~_PAGE_NX;
-}
-
 int force_personality32;
 
 /*
@@ -628,6 +585,7 @@ void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn)
        early_res_to_bootmem(0, end_pfn<<PAGE_SHIFT);
        reserve_bootmem(bootmap, bootmap_size, BOOTMEM_DEFAULT);
 }
+#endif
 
 void __init paging_init(void)
 {
@@ -638,11 +596,10 @@ void __init paging_init(void)
        max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN;
        max_zone_pfns[ZONE_NORMAL] = max_pfn;
 
-       memory_present(0, 0, max_pfn);
+       sparse_memory_present_with_active_regions(MAX_NUMNODES);
        sparse_init();
        free_area_init_nodes(max_zone_pfns);
 }
-#endif
 
 /*
  * Memory hotplug specific functions
index 8056545e2d39f9b53ba56349db4717809d6b9f04..fe6f84ca121ee072d2be8014e2b9b7e959e5abbd 100644 (file)
@@ -82,7 +82,6 @@ iounmap_atomic(void *kvaddr, enum km_type type)
        if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx))
                kpte_clear_flush(kmap_pte-idx, vaddr);
 
-       arch_flush_lazy_mmu_mode();
        pagefault_enable();
 }
 EXPORT_SYMBOL_GPL(iounmap_atomic);
index 50dc802a1c469b904154be3901f5fc87ebd7da93..16ccbd77917f22c1693b9b41fcb8dc7485acee39 100644 (file)
@@ -32,7 +32,7 @@ struct kmmio_fault_page {
        struct list_head list;
        struct kmmio_fault_page *release_next;
        unsigned long page; /* location of the fault page */
-       bool old_presence; /* page presence prior to arming */
+       pteval_t old_presence; /* page presence prior to arming */
        bool armed;
 
        /*
@@ -97,60 +97,62 @@ static struct kmmio_probe *get_kmmio_probe(unsigned long addr)
 static struct kmmio_fault_page *get_kmmio_fault_page(unsigned long page)
 {
        struct list_head *head;
-       struct kmmio_fault_page *p;
+       struct kmmio_fault_page *f;
 
        page &= PAGE_MASK;
        head = kmmio_page_list(page);
-       list_for_each_entry_rcu(p, head, list) {
-               if (p->page == page)
-                       return p;
+       list_for_each_entry_rcu(f, head, list) {
+               if (f->page == page)
+                       return f;
        }
        return NULL;
 }
 
-static void set_pmd_presence(pmd_t *pmd, bool present, bool *old)
+static void clear_pmd_presence(pmd_t *pmd, bool clear, pmdval_t *old)
 {
        pmdval_t v = pmd_val(*pmd);
-       *old = !!(v & _PAGE_PRESENT);
-       v &= ~_PAGE_PRESENT;
-       if (present)
-               v |= _PAGE_PRESENT;
+       if (clear) {
+               *old = v & _PAGE_PRESENT;
+               v &= ~_PAGE_PRESENT;
+       } else  /* presume this has been called with clear==true previously */
+               v |= *old;
        set_pmd(pmd, __pmd(v));
 }
 
-static void set_pte_presence(pte_t *pte, bool present, bool *old)
+static void clear_pte_presence(pte_t *pte, bool clear, pteval_t *old)
 {
        pteval_t v = pte_val(*pte);
-       *old = !!(v & _PAGE_PRESENT);
-       v &= ~_PAGE_PRESENT;
-       if (present)
-               v |= _PAGE_PRESENT;
+       if (clear) {
+               *old = v & _PAGE_PRESENT;
+               v &= ~_PAGE_PRESENT;
+       } else  /* presume this has been called with clear==true previously */
+               v |= *old;
        set_pte_atomic(pte, __pte(v));
 }
 
-static int set_page_presence(unsigned long addr, bool present, bool *old)
+static int clear_page_presence(struct kmmio_fault_page *f, bool clear)
 {
        unsigned int level;
-       pte_t *pte = lookup_address(addr, &level);
+       pte_t *pte = lookup_address(f->page, &level);
 
        if (!pte) {
-               pr_err("kmmio: no pte for page 0x%08lx\n", addr);
+               pr_err("kmmio: no pte for page 0x%08lx\n", f->page);
                return -1;
        }
 
        switch (level) {
        case PG_LEVEL_2M:
-               set_pmd_presence((pmd_t *)pte, present, old);
+               clear_pmd_presence((pmd_t *)pte, clear, &f->old_presence);
                break;
        case PG_LEVEL_4K:
-               set_pte_presence(pte, present, old);
+               clear_pte_presence(pte, clear, &f->old_presence);
                break;
        default:
                pr_err("kmmio: unexpected page level 0x%x.\n", level);
                return -1;
        }
 
-       __flush_tlb_one(addr);
+       __flush_tlb_one(f->page);
        return 0;
 }
 
@@ -171,9 +173,9 @@ static int arm_kmmio_fault_page(struct kmmio_fault_page *f)
        WARN_ONCE(f->armed, KERN_ERR "kmmio page already armed.\n");
        if (f->armed) {
                pr_warning("kmmio double-arm: page 0x%08lx, ref %d, old %d\n",
-                                       f->page, f->count, f->old_presence);
+                                       f->page, f->count, !!f->old_presence);
        }
-       ret = set_page_presence(f->page, false, &f->old_presence);
+       ret = clear_page_presence(f, true);
        WARN_ONCE(ret < 0, KERN_ERR "kmmio arming 0x%08lx failed.\n", f->page);
        f->armed = true;
        return ret;
@@ -182,8 +184,7 @@ static int arm_kmmio_fault_page(struct kmmio_fault_page *f)
 /** Restore the given page to saved presence state. */
 static void disarm_kmmio_fault_page(struct kmmio_fault_page *f)
 {
-       bool tmp;
-       int ret = set_page_presence(f->page, f->old_presence, &tmp);
+       int ret = clear_page_presence(f, false);
        WARN_ONCE(ret < 0,
                        KERN_ERR "kmmio disarming 0x%08lx failed.\n", f->page);
        f->armed = false;
@@ -310,7 +311,12 @@ static int post_kmmio_handler(unsigned long condition, struct pt_regs *regs)
        struct kmmio_context *ctx = &get_cpu_var(kmmio_ctx);
 
        if (!ctx->active) {
-               pr_debug("kmmio: spurious debug trap on CPU %d.\n",
+               /*
+                * debug traps without an active context are due to either
+                * something external causing them (f.e. using a debugger while
+                * mmio tracing enabled), or erroneous behaviour
+                */
+               pr_warning("kmmio: unexpected debug trap on CPU %d.\n",
                                                        smp_processor_id());
                goto out;
        }
@@ -439,12 +445,12 @@ static void rcu_free_kmmio_fault_pages(struct rcu_head *head)
                                                head,
                                                struct kmmio_delayed_release,
                                                rcu);
-       struct kmmio_fault_page *p = dr->release_list;
-       while (p) {
-               struct kmmio_fault_page *next = p->release_next;
-               BUG_ON(p->count);
-               kfree(p);
-               p = next;
+       struct kmmio_fault_page *f = dr->release_list;
+       while (f) {
+               struct kmmio_fault_page *next = f->release_next;
+               BUG_ON(f->count);
+               kfree(f);
+               f = next;
        }
        kfree(dr);
 }
@@ -453,19 +459,19 @@ static void remove_kmmio_fault_pages(struct rcu_head *head)
 {
        struct kmmio_delayed_release *dr =
                container_of(head, struct kmmio_delayed_release, rcu);
-       struct kmmio_fault_page *p = dr->release_list;
+       struct kmmio_fault_page *f = dr->release_list;
        struct kmmio_fault_page **prevp = &dr->release_list;
        unsigned long flags;
 
        spin_lock_irqsave(&kmmio_lock, flags);
-       while (p) {
-               if (!p->count) {
-                       list_del_rcu(&p->list);
-                       prevp = &p->release_next;
+       while (f) {
+               if (!f->count) {
+                       list_del_rcu(&f->list);
+                       prevp = &f->release_next;
                } else {
-                       *prevp = p->release_next;
+                       *prevp = f->release_next;
                }
-               p = p->release_next;
+               f = f->release_next;
        }
        spin_unlock_irqrestore(&kmmio_lock, flags);
 
@@ -528,8 +534,8 @@ void unregister_kmmio_probe(struct kmmio_probe *p)
 }
 EXPORT_SYMBOL(unregister_kmmio_probe);
 
-static int kmmio_die_notifier(struct notifier_block *nb, unsigned long val,
-                                                               void *args)
+static int
+kmmio_die_notifier(struct notifier_block *nb, unsigned long val, void *args)
 {
        struct die_args *arg = args;
 
@@ -544,11 +550,23 @@ static struct notifier_block nb_die = {
        .notifier_call = kmmio_die_notifier
 };
 
-static int __init init_kmmio(void)
+int kmmio_init(void)
 {
        int i;
+
        for (i = 0; i < KMMIO_PAGE_TABLE_SIZE; i++)
                INIT_LIST_HEAD(&kmmio_page_table[i]);
+
        return register_die_notifier(&nb_die);
 }
-fs_initcall(init_kmmio); /* should be before device_initcall() */
+
+void kmmio_cleanup(void)
+{
+       int i;
+
+       unregister_die_notifier(&nb_die);
+       for (i = 0; i < KMMIO_PAGE_TABLE_SIZE; i++) {
+               WARN_ONCE(!list_empty(&kmmio_page_table[i]),
+                       KERN_ERR "kmmio_page_table not empty at cleanup, any further tracing will leak memory.\n");
+       }
+}
index 605c8be06217b0da36344abd5f23d06326bcd87a..c0bedcd10f9733a3a9a21873b9043ead3a87546e 100644 (file)
@@ -40,23 +40,23 @@ static void __init reserve_bad_mem(u64 pattern, u64 start_bad, u64 end_bad)
 
 static void __init memtest(u64 pattern, u64 start_phys, u64 size)
 {
-       u64 i, count;
-       u64 *start;
+       u64 *p;
+       void *start, *end;
        u64 start_bad, last_bad;
        u64 start_phys_aligned;
        size_t incr;
 
        incr = sizeof(pattern);
        start_phys_aligned = ALIGN(start_phys, incr);
-       count = (size - (start_phys_aligned - start_phys))/incr;
        start = __va(start_phys_aligned);
+       end = start + size - (start_phys_aligned - start_phys);
        start_bad = 0;
        last_bad = 0;
 
-       for (i = 0; i < count; i++)
-               start[i] = pattern;
-       for (i = 0; i < count; i++, start++, start_phys_aligned += incr) {
-               if (*start == pattern)
+       for (p = start; p < end; p++)
+               *p = pattern;
+       for (p = start; p < end; p++, start_phys_aligned += incr) {
+               if (*p == pattern)
                        continue;
                if (start_phys_aligned == last_bad + incr) {
                        last_bad += incr;
index c9342ed8b402dd93cc2e991ac1f44f67a0261c8d..132772a8ec57a66c629ad5719431fa6c08d95d98 100644 (file)
@@ -451,6 +451,7 @@ void enable_mmiotrace(void)
 
        if (nommiotrace)
                pr_info(NAME "MMIO tracing disabled.\n");
+       kmmio_init();
        enter_uniprocessor();
        spin_lock_irq(&trace_lock);
        atomic_inc(&mmiotrace_enabled);
@@ -473,6 +474,7 @@ void disable_mmiotrace(void)
 
        clear_trace_list(); /* guarantees: no more kmmio callbacks */
        leave_uniprocessor();
+       kmmio_cleanup();
        pr_info(NAME "disabled.\n");
 out:
        mutex_unlock(&mmiotrace_mutex);
index 2d05a12029dc3d216814eb2a9e914b389014407a..459913beac71dc0539a4f0bd11a299df869e5711 100644 (file)
@@ -179,18 +179,25 @@ static void * __init early_node_mem(int nodeid, unsigned long start,
 }
 
 /* Initialize bootmem allocator for a node */
-void __init setup_node_bootmem(int nodeid, unsigned long start,
-                              unsigned long end)
+void __init
+setup_node_bootmem(int nodeid, unsigned long start, unsigned long end)
 {
        unsigned long start_pfn, last_pfn, bootmap_pages, bootmap_size;
+       const int pgdat_size = roundup(sizeof(pg_data_t), PAGE_SIZE);
        unsigned long bootmap_start, nodedata_phys;
        void *bootmap;
-       const int pgdat_size = roundup(sizeof(pg_data_t), PAGE_SIZE);
        int nid;
 
        if (!end)
                return;
 
+       /*
+        * Don't confuse VM with a node that doesn't have the
+        * minimum amount of memory:
+        */
+       if (end && (end - start) < NODE_MIN_SIZE)
+               return;
+
        start = roundup(start, ZONE_ALIGN);
 
        printk(KERN_INFO "Bootmem setup node %d %016lx-%016lx\n", nodeid,
@@ -272,9 +279,6 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
                reserve_bootmem_node(NODE_DATA(nodeid), bootmap_start,
                                 bootmap_pages<<PAGE_SHIFT, BOOTMEM_DEFAULT);
 
-#ifdef CONFIG_ACPI_NUMA
-       srat_reserve_add_area(nodeid);
-#endif
        node_set_online(nodeid);
 }
 
@@ -578,21 +582,6 @@ unsigned long __init numa_free_all_bootmem(void)
        return pages;
 }
 
-void __init paging_init(void)
-{
-       unsigned long max_zone_pfns[MAX_NR_ZONES];
-
-       memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
-       max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN;
-       max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN;
-       max_zone_pfns[ZONE_NORMAL] = max_pfn;
-
-       sparse_memory_present_with_active_regions(MAX_NUMNODES);
-       sparse_init();
-
-       free_area_init_nodes(max_zone_pfns);
-}
-
 static __init int numa_setup(char *opt)
 {
        if (!opt)
@@ -606,8 +595,6 @@ static __init int numa_setup(char *opt)
 #ifdef CONFIG_ACPI_NUMA
        if (!strncmp(opt, "noacpi", 6))
                acpi_numa = -1;
-       if (!strncmp(opt, "hotadd=", 7))
-               hotadd_percent = simple_strtoul(opt+7, NULL, 10);
 #endif
        return 0;
 }
index e17efed088c54a7b546b7b76c073ab55231d425e..6ce9518fe2acb6457db7d6c19c1739e6f48f2c9b 100644 (file)
@@ -839,13 +839,6 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
 
        vm_unmap_aliases();
 
-       /*
-        * If we're called with lazy mmu updates enabled, the
-        * in-memory pte state may be stale.  Flush pending updates to
-        * bring them up to date.
-        */
-       arch_flush_lazy_mmu_mode();
-
        cpa.vaddr = addr;
        cpa.pages = pages;
        cpa.numpages = numpages;
@@ -890,13 +883,6 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
        } else
                cpa_flush_all(cache);
 
-       /*
-        * If we've been called with lazy mmu updates enabled, then
-        * make sure that everything gets flushed out before we
-        * return.
-        */
-       arch_flush_lazy_mmu_mode();
-
 out:
        return ret;
 }
index 01765955baaf66922ad70a959c9875f60fcad56e..2dfcbf9df2ae8410228e25fb4f559cd75ed1982e 100644 (file)
@@ -31,17 +31,11 @@ static nodemask_t nodes_parsed __initdata;
 static nodemask_t cpu_nodes_parsed __initdata;
 static struct bootnode nodes[MAX_NUMNODES] __initdata;
 static struct bootnode nodes_add[MAX_NUMNODES];
-static int found_add_area __initdata;
-int hotadd_percent __initdata = 0;
 
 static int num_node_memblks __initdata;
 static struct bootnode node_memblk_range[NR_NODE_MEMBLKS] __initdata;
 static int memblk_nodeid[NR_NODE_MEMBLKS] __initdata;
 
-/* Too small nodes confuse the VM badly. Usually they result
-   from BIOS bugs. */
-#define NODE_MIN_SIZE (4*1024*1024)
-
 static __init int setup_node(int pxm)
 {
        return acpi_map_pxm_to_node(pxm);
@@ -66,9 +60,6 @@ static __init void cutoff_node(int i, unsigned long start, unsigned long end)
 {
        struct bootnode *nd = &nodes[i];
 
-       if (found_add_area)
-               return;
-
        if (nd->start < start) {
                nd->start = start;
                if (nd->end < nd->start)
@@ -86,7 +77,6 @@ static __init void bad_srat(void)
        int i;
        printk(KERN_ERR "SRAT: SRAT not used.\n");
        acpi_numa = -1;
-       found_add_area = 0;
        for (i = 0; i < MAX_LOCAL_APIC; i++)
                apicid_to_node[i] = NUMA_NO_NODE;
        for (i = 0; i < MAX_NUMNODES; i++)
@@ -182,24 +172,21 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
               pxm, apic_id, node);
 }
 
-static int update_end_of_memory(unsigned long end) {return -1;}
-static int hotadd_enough_memory(struct bootnode *nd) {return 1;}
 #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
 static inline int save_add_info(void) {return 1;}
 #else
 static inline int save_add_info(void) {return 0;}
 #endif
 /*
- * Update nodes_add and decide if to include add are in the zone.
- * Both SPARSE and RESERVE need nodes_add information.
- * This code supports one contiguous hot add area per node.
+ * Update nodes_add[]
+ * This code supports one contiguous hot add area per node
  */
-static int __init
-reserve_hotadd(int node, unsigned long start, unsigned long end)
+static void __init
+update_nodes_add(int node, unsigned long start, unsigned long end)
 {
        unsigned long s_pfn = start >> PAGE_SHIFT;
        unsigned long e_pfn = end >> PAGE_SHIFT;
-       int ret = 0, changed = 0;
+       int changed = 0;
        struct bootnode *nd = &nodes_add[node];
 
        /* I had some trouble with strange memory hotadd regions breaking
@@ -210,7 +197,7 @@ reserve_hotadd(int node, unsigned long start, unsigned long end)
           mistakes */
        if ((signed long)(end - start) < NODE_MIN_SIZE) {
                printk(KERN_ERR "SRAT: Hotplug area too small\n");
-               return -1;
+               return;
        }
 
        /* This check might be a bit too strict, but I'm keeping it for now. */
@@ -218,12 +205,7 @@ reserve_hotadd(int node, unsigned long start, unsigned long end)
                printk(KERN_ERR
                        "SRAT: Hotplug area %lu -> %lu has existing memory\n",
                        s_pfn, e_pfn);
-               return -1;
-       }
-
-       if (!hotadd_enough_memory(&nodes_add[node]))  {
-               printk(KERN_ERR "SRAT: Hotplug area too large\n");
-               return -1;
+               return;
        }
 
        /* Looks good */
@@ -245,11 +227,9 @@ reserve_hotadd(int node, unsigned long start, unsigned long end)
                        printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n");
        }
 
-       ret = update_end_of_memory(nd->end);
-
        if (changed)
-               printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n", nd->start, nd->end);
-       return ret;
+               printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n",
+                                nd->start, nd->end);
 }
 
 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
@@ -310,13 +290,10 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
               start, end);
        e820_register_active_regions(node, start >> PAGE_SHIFT,
                                     end >> PAGE_SHIFT);
-       push_node_boundaries(node, nd->start >> PAGE_SHIFT,
-                                               nd->end >> PAGE_SHIFT);
 
-       if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) &&
-           (reserve_hotadd(node, start, end) < 0)) {
-               /* Ignore hotadd region. Undo damage */
-               printk(KERN_NOTICE "SRAT: Hotplug region ignored\n");
+       if (ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) {
+               update_nodes_add(node, start, end);
+               /* restore nodes[node] */
                *nd = oldnode;
                if ((nd->start | nd->end) == 0)
                        node_clear(node, nodes_parsed);
@@ -345,9 +322,9 @@ static int __init nodes_cover_memory(const struct bootnode *nodes)
                        pxmram = 0;
        }
 
-       e820ram = max_pfn - absent_pages_in_range(0, max_pfn);
-       /* We seem to lose 3 pages somewhere. Allow a bit of slack. */
-       if ((long)(e820ram - pxmram) >= 1*1024*1024) {
+       e820ram = max_pfn - (e820_hole_size(0, max_pfn<<PAGE_SHIFT)>>PAGE_SHIFT);
+       /* We seem to lose 3 pages somewhere. Allow 1M of slack. */
+       if ((long)(e820ram - pxmram) >= (1<<(20 - PAGE_SHIFT))) {
                printk(KERN_ERR
        "SRAT: PXMs only cover %luMB of your %luMB e820 RAM. Not used.\n",
                        (pxmram << PAGE_SHIFT) >> 20,
@@ -357,17 +334,6 @@ static int __init nodes_cover_memory(const struct bootnode *nodes)
        return 1;
 }
 
-static void __init unparse_node(int node)
-{
-       int i;
-       node_clear(node, nodes_parsed);
-       node_clear(node, cpu_nodes_parsed);
-       for (i = 0; i < MAX_LOCAL_APIC; i++) {
-               if (apicid_to_node[i] == node)
-                       apicid_to_node[i] = NUMA_NO_NODE;
-       }
-}
-
 void __init acpi_numa_arch_fixup(void) {}
 
 /* Use the information discovered above to actually set up the nodes. */
@@ -379,18 +345,8 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
                return -1;
 
        /* First clean up the node list */
-       for (i = 0; i < MAX_NUMNODES; i++) {
+       for (i = 0; i < MAX_NUMNODES; i++)
                cutoff_node(i, start, end);
-               /*
-                * don't confuse VM with a node that doesn't have the
-                * minimum memory.
-                */
-               if (nodes[i].end &&
-                       (nodes[i].end - nodes[i].start) < NODE_MIN_SIZE) {
-                       unparse_node(i);
-                       node_set_offline(i);
-               }
-       }
 
        if (!nodes_cover_memory(nodes)) {
                bad_srat();
@@ -423,7 +379,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
 
                if (node == NUMA_NO_NODE)
                        continue;
-               if (!node_isset(node, node_possible_map))
+               if (!node_online(node))
                        numa_clear_node(i);
        }
        numa_init_array();
@@ -510,26 +466,6 @@ static int null_slit_node_compare(int a, int b)
 }
 #endif /* CONFIG_NUMA_EMU */
 
-void __init srat_reserve_add_area(int nodeid)
-{
-       if (found_add_area && nodes_add[nodeid].end) {
-               u64 total_mb;
-
-               printk(KERN_INFO "SRAT: Reserving hot-add memory space "
-                               "for node %d at %Lx-%Lx\n",
-                       nodeid, nodes_add[nodeid].start, nodes_add[nodeid].end);
-               total_mb = (nodes_add[nodeid].end - nodes_add[nodeid].start)
-                                       >> PAGE_SHIFT;
-               total_mb *= sizeof(struct page);
-               total_mb >>= 20;
-               printk(KERN_INFO "SRAT: This will cost you %Lu MB of "
-                               "pre-allocated memory.\n", (unsigned long long)total_mb);
-               reserve_bootmem_node(NODE_DATA(nodeid), nodes_add[nodeid].start,
-                              nodes_add[nodeid].end - nodes_add[nodeid].start,
-                              BOOTMEM_DEFAULT);
-       }
-}
-
 int __node_distance(int a, int b)
 {
        int index;
index 202864ad49a7e5bf2a6574922d7cd938dd023fd9..3b285e656e27e57dbf4ae6dd35b715d7c9f2d1c7 100644 (file)
@@ -356,14 +356,11 @@ static void exit_sysfs(void)
 #define exit_sysfs() do { } while (0)
 #endif /* CONFIG_PM */
 
-static int p4force;
-module_param(p4force, int, 0);
-
 static int __init p4_init(char **cpu_type)
 {
        __u8 cpu_model = boot_cpu_data.x86_model;
 
-       if (!p4force && (cpu_model > 6 || cpu_model == 5))
+       if (cpu_model > 6 || cpu_model == 5)
                return 0;
 
 #ifndef CONFIG_SMP
@@ -389,10 +386,25 @@ static int __init p4_init(char **cpu_type)
        return 0;
 }
 
+static int force_arch_perfmon;
+static int force_cpu_type(const char *str, struct kernel_param *kp)
+{
+       if (!strcmp(str, "archperfmon")) {
+               force_arch_perfmon = 1;
+               printk(KERN_INFO "oprofile: forcing architectural perfmon\n");
+       }
+
+       return 0;
+}
+module_param_call(cpu_type, force_cpu_type, NULL, NULL, 0);
+
 static int __init ppro_init(char **cpu_type)
 {
        __u8 cpu_model = boot_cpu_data.x86_model;
 
+       if (force_arch_perfmon && cpu_has_arch_perfmon)
+               return 0;
+
        switch (cpu_model) {
        case 0 ... 2:
                *cpu_type = "i386/ppro";
@@ -414,6 +426,13 @@ static int __init ppro_init(char **cpu_type)
        case 15: case 23:
                *cpu_type = "i386/core_2";
                break;
+       case 26:
+               arch_perfmon_setup_counters();
+               *cpu_type = "i386/core_i7";
+               break;
+       case 28:
+               *cpu_type = "i386/atom";
+               break;
        default:
                /* Unknown */
                return 0;
index fecbce6e7d7c20d1f0af750e2305ef4e9a37a92c..0696d506c4ade99b0d43232128a77cea99d65ec8 100644 (file)
@@ -889,6 +889,9 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
                return 0;
        }
 
+       if (io_apic_assign_pci_irqs)
+               return 0;
+
        /* Find IRQ routing entry */
 
        if (!pirq_table)
@@ -1039,56 +1042,15 @@ static void __init pcibios_fixup_irqs(void)
                pirq_penalty[dev->irq]++;
        }
 
+       if (io_apic_assign_pci_irqs)
+               return;
+
        dev = NULL;
        while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
                pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
                if (!pin)
                        continue;
 
-#ifdef CONFIG_X86_IO_APIC
-               /*
-                * Recalculate IRQ numbers if we use the I/O APIC.
-                */
-               if (io_apic_assign_pci_irqs) {
-                       int irq;
-
-                       /*
-                        * interrupt pins are numbered starting from 1
-                        */
-                       irq = IO_APIC_get_PCI_irq_vector(dev->bus->number,
-                               PCI_SLOT(dev->devfn), pin - 1);
-                       /*
-                        * Busses behind bridges are typically not listed in the
-                        * MP-table.  In this case we have to look up the IRQ
-                        * based on the parent bus, parent slot, and pin number.
-                        * The SMP code detects such bridged busses itself so we
-                        * should get into this branch reliably.
-                        */
-                       if (irq < 0 && dev->bus->parent) {
-                               /* go back to the bridge */
-                               struct pci_dev *bridge = dev->bus->self;
-                               int bus;
-
-                               pin = pci_swizzle_interrupt_pin(dev, pin);
-                               bus = bridge->bus->number;
-                               irq = IO_APIC_get_PCI_irq_vector(bus,
-                                               PCI_SLOT(bridge->devfn), pin - 1);
-                               if (irq >= 0)
-                                       dev_warn(&dev->dev,
-                                               "using bridge %s INT %c to "
-                                                       "get IRQ %d\n",
-                                                pci_name(bridge),
-                                                'A' + pin - 1, irq);
-                       }
-                       if (irq >= 0) {
-                               dev_info(&dev->dev,
-                                       "PCI->APIC IRQ transform: INT %c "
-                                               "-> IRQ %d\n",
-                                       'A' + pin - 1, irq);
-                               dev->irq = irq;
-                       }
-               }
-#endif
                /*
                 * Still no IRQ? Try to lookup one...
                 */
@@ -1183,6 +1145,19 @@ int __init pcibios_irq_init(void)
        pcibios_enable_irq = pirq_enable_irq;
 
        pcibios_fixup_irqs();
+
+       if (io_apic_assign_pci_irqs && pci_routeirq) {
+               struct pci_dev *dev = NULL;
+               /*
+                * PCI IRQ routing is set up by pci_enable_device(), but we
+                * also do it here in case there are still broken drivers that
+                * don't use pci_enable_device().
+                */
+               printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified\n");
+               for_each_pci_dev(dev)
+                       pirq_enable_irq(dev);
+       }
+
        return 0;
 }
 
@@ -1213,16 +1188,23 @@ void pcibios_penalize_isa_irq(int irq, int active)
 static int pirq_enable_irq(struct pci_dev *dev)
 {
        u8 pin;
-       struct pci_dev *temp_dev;
 
        pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-       if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
+       if (pin && !pcibios_lookup_irq(dev, 1)) {
                char *msg = "";
 
+               if (!io_apic_assign_pci_irqs && dev->irq)
+                       return 0;
+
                if (io_apic_assign_pci_irqs) {
+#ifdef CONFIG_X86_IO_APIC
+                       struct pci_dev *temp_dev;
                        int irq;
+                       struct io_apic_irq_attr irq_attr;
 
-                       irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin - 1);
+                       irq = IO_APIC_get_PCI_irq_vector(dev->bus->number,
+                                               PCI_SLOT(dev->devfn),
+                                               pin - 1, &irq_attr);
                        /*
                         * Busses behind bridges are typically not listed in the MP-table.
                         * In this case we have to look up the IRQ based on the parent bus,
@@ -1235,7 +1217,8 @@ static int pirq_enable_irq(struct pci_dev *dev)
 
                                pin = pci_swizzle_interrupt_pin(dev, pin);
                                irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number,
-                                               PCI_SLOT(bridge->devfn), pin - 1);
+                                               PCI_SLOT(bridge->devfn),
+                                               pin - 1, &irq_attr);
                                if (irq >= 0)
                                        dev_warn(&dev->dev, "using bridge %s "
                                                 "INT %c to get IRQ %d\n",
@@ -1245,12 +1228,15 @@ static int pirq_enable_irq(struct pci_dev *dev)
                        }
                        dev = temp_dev;
                        if (irq >= 0) {
+                               io_apic_set_pci_routing(&dev->dev, irq,
+                                                        &irq_attr);
+                               dev->irq = irq;
                                dev_info(&dev->dev, "PCI->APIC IRQ transform: "
                                         "INT %c -> IRQ %d\n", 'A' + pin - 1, irq);
-                               dev->irq = irq;
                                return 0;
                        } else
                                msg = "; probably buggy MP table";
+#endif
                } else if (pci_probe & PCI_BIOS_IRQ_SCAN)
                        msg = "";
                else
index 7133cdf9098b7ef0366871a92c29ef8aa5445209..cac083386e0339801940daf8463a91df40f35721 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/random.h>
+#include <linux/elf.h>
 #include <asm/vsyscall.h>
 #include <asm/vgtod.h>
 #include <asm/proto.h>
index f09e8c36ee805d58ba0d6580397305744446cc42..0a1700a2be9c8c9a548822ca4deef1bb475b4059 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/start_kernel.h>
 #include <linux/sched.h>
+#include <linux/kprobes.h>
 #include <linux/bootmem.h>
 #include <linux/module.h>
 #include <linux/mm.h>
@@ -44,6 +45,7 @@
 #include <asm/processor.h>
 #include <asm/proto.h>
 #include <asm/msr-index.h>
+#include <asm/traps.h>
 #include <asm/setup.h>
 #include <asm/desc.h>
 #include <asm/pgtable.h>
@@ -240,10 +242,10 @@ static unsigned long xen_get_debugreg(int reg)
        return HYPERVISOR_get_debugreg(reg);
 }
 
-void xen_leave_lazy(void)
+static void xen_end_context_switch(struct task_struct *next)
 {
-       paravirt_leave_lazy(paravirt_get_lazy_mode());
        xen_mc_flush();
+       paravirt_end_context_switch(next);
 }
 
 static unsigned long xen_store_tr(void)
@@ -428,11 +430,44 @@ static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum,
 static int cvt_gate_to_trap(int vector, const gate_desc *val,
                            struct trap_info *info)
 {
+       unsigned long addr;
+
        if (val->type != GATE_TRAP && val->type != GATE_INTERRUPT)
                return 0;
 
        info->vector = vector;
-       info->address = gate_offset(*val);
+
+       addr = gate_offset(*val);
+#ifdef CONFIG_X86_64
+       /*
+        * Look for known traps using IST, and substitute them
+        * appropriately.  The debugger ones are the only ones we care
+        * about.  Xen will handle faults like double_fault and
+        * machine_check, so we should never see them.  Warn if
+        * there's an unexpected IST-using fault handler.
+        */
+       if (addr == (unsigned long)debug)
+               addr = (unsigned long)xen_debug;
+       else if (addr == (unsigned long)int3)
+               addr = (unsigned long)xen_int3;
+       else if (addr == (unsigned long)stack_segment)
+               addr = (unsigned long)xen_stack_segment;
+       else if (addr == (unsigned long)double_fault ||
+                addr == (unsigned long)nmi) {
+               /* Don't need to handle these */
+               return 0;
+#ifdef CONFIG_X86_MCE
+       } else if (addr == (unsigned long)machine_check) {
+               return 0;
+#endif
+       } else {
+               /* Some other trap using IST? */
+               if (WARN_ON(val->ist != 0))
+                       return 0;
+       }
+#endif /* CONFIG_X86_64 */
+       info->address = addr;
+
        info->cs = gate_segment(*val);
        info->flags = val->dpl;
        /* interrupt gates clear IF */
@@ -623,10 +658,26 @@ static void xen_clts(void)
        xen_mc_issue(PARAVIRT_LAZY_CPU);
 }
 
+static DEFINE_PER_CPU(unsigned long, xen_cr0_value);
+
+static unsigned long xen_read_cr0(void)
+{
+       unsigned long cr0 = percpu_read(xen_cr0_value);
+
+       if (unlikely(cr0 == 0)) {
+               cr0 = native_read_cr0();
+               percpu_write(xen_cr0_value, cr0);
+       }
+
+       return cr0;
+}
+
 static void xen_write_cr0(unsigned long cr0)
 {
        struct multicall_space mcs;
 
+       percpu_write(xen_cr0_value, cr0);
+
        /* Only pay attention to cr0.TS; everything else is
           ignored. */
        mcs = xen_mc_entry(0);
@@ -812,7 +863,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
 
        .clts = xen_clts,
 
-       .read_cr0 = native_read_cr0,
+       .read_cr0 = xen_read_cr0,
        .write_cr0 = xen_write_cr0,
 
        .read_cr4 = native_read_cr4,
@@ -860,10 +911,8 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
        /* Xen takes care of %gs when switching to usermode for us */
        .swapgs = paravirt_nop,
 
-       .lazy_mode = {
-               .enter = paravirt_enter_lazy_cpu,
-               .leave = xen_leave_lazy,
-       },
+       .start_context_switch = paravirt_start_context_switch,
+       .end_context_switch = xen_end_context_switch,
 };
 
 static const struct pv_apic_ops xen_apic_ops __initdata = {
index fba55b1a40217f93dad87242d3d7584a5d9665b2..4ceb28581652ef0ab7ff7bcc5426dd914954d100 100644 (file)
@@ -452,10 +452,6 @@ void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags)
 void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
                    pte_t *ptep, pte_t pteval)
 {
-       /* updates to init_mm may be done without lock */
-       if (mm == &init_mm)
-               preempt_disable();
-
        ADD_STATS(set_pte_at, 1);
 //     ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep));
        ADD_STATS(set_pte_at_current, mm == current->mm);
@@ -476,9 +472,7 @@ void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
        }
        xen_set_pte(ptep, pteval);
 
-out:
-       if (mm == &init_mm)
-               preempt_enable();
+out:   return;
 }
 
 pte_t xen_ptep_modify_prot_start(struct mm_struct *mm,
@@ -1152,10 +1146,8 @@ static void drop_other_mm_ref(void *info)
 
        /* If this cpu still has a stale cr3 reference, then make sure
           it has been flushed. */
-       if (percpu_read(xen_current_cr3) == __pa(mm->pgd)) {
+       if (percpu_read(xen_current_cr3) == __pa(mm->pgd))
                load_cr3(swapper_pg_dir);
-               arch_flush_lazy_cpu_mode();
-       }
 }
 
 static void xen_drop_mm_ref(struct mm_struct *mm)
@@ -1168,7 +1160,6 @@ static void xen_drop_mm_ref(struct mm_struct *mm)
                        load_cr3(swapper_pg_dir);
                else
                        leave_mm(smp_processor_id());
-               arch_flush_lazy_cpu_mode();
        }
 
        /* Get the "official" set of cpus referring to our pagetable. */
@@ -1876,6 +1867,14 @@ __init void xen_post_allocator_init(void)
        xen_mark_init_mm_pinned();
 }
 
+static void xen_leave_lazy_mmu(void)
+{
+       preempt_disable();
+       xen_mc_flush();
+       paravirt_leave_lazy_mmu();
+       preempt_enable();
+}
+
 const struct pv_mmu_ops xen_mmu_ops __initdata = {
        .pagetable_setup_start = xen_pagetable_setup_start,
        .pagetable_setup_done = xen_pagetable_setup_done,
@@ -1949,7 +1948,7 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = {
 
        .lazy_mode = {
                .enter = paravirt_enter_lazy_mmu,
-               .leave = xen_leave_lazy,
+               .leave = xen_leave_lazy_mmu,
        },
 
        .set_fixmap = xen_set_fixmap,
index 15c6c68db6a25f4941d25e8fc35857a3d518dc5d..ad0047f47cd476004c99485877f6d62a7db20d86 100644 (file)
@@ -61,9 +61,9 @@ char * __init xen_memory_setup(void)
         *  - xen_start_info
         * See comment above "struct start_info" in <xen/interface/xen.h>
         */
-       e820_add_region(__pa(xen_start_info->mfn_list),
-                       xen_start_info->pt_base - xen_start_info->mfn_list,
-                       E820_RESERVED);
+       reserve_early(__pa(xen_start_info->mfn_list),
+                     __pa(xen_start_info->pt_base),
+                       "XEN START INFO");
 
        sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
 
index ca6596b05d533c25f56e242409e88471a816ba9c..22494fd4c9b5cf49f8b3af7b2999626dc750b80c 100644 (file)
@@ -30,7 +30,6 @@ pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn);
 void xen_ident_map_ISA(void);
 void xen_reserve_top(void);
 
-void xen_leave_lazy(void);
 void xen_post_allocator_init(void);
 
 char * __init xen_memory_setup(void);
index e7d12782bcfb5eccb56aee532b8c27fa81706499..2c39527aa7db026dc6c6b6c20fbe55024de46100 100644 (file)
@@ -26,6 +26,7 @@ if BLOCK
 config LBD
        bool "Support for large block devices and files"
        depends on !64BIT
+       default y
        help
          Enable block devices or files of size 2TB and larger.
 
@@ -38,11 +39,13 @@ config LBD
 
          The ext4 filesystem requires that this feature be enabled in
          order to support filesystems that have the huge_file feature
-         enabled.    Otherwise, it will refuse to mount any filesystems
-         that use the huge_file feature, which is enabled by default
-         by mke2fs.ext4.   The GFS2 filesystem also requires this feature.
+         enabled.  Otherwise, it will refuse to mount in the read-write
+         mode any filesystems that use the huge_file feature, which is
+         enabled by default by mke2fs.ext4.
 
-         If unsure, say N.
+         The GFS2 filesystem also requires this feature.
+
+         If unsure, say Y.
 
 config BLK_DEV_BSG
        bool "Block layer SG support v4 (EXPERIMENTAL)"
index c48fa670d221342f223d196ab12e17d67452fe89..7a12cf6ee1d35e212a6d26007a1eb2057c189357 100644 (file)
@@ -306,8 +306,8 @@ as_choose_req(struct as_data *ad, struct request *rq1, struct request *rq2)
        data_dir = rq_is_sync(rq1);
 
        last = ad->last_sector[data_dir];
-       s1 = rq1->sector;
-       s2 = rq2->sector;
+       s1 = blk_rq_pos(rq1);
+       s2 = blk_rq_pos(rq2);
 
        BUG_ON(data_dir != rq_is_sync(rq2));
 
@@ -566,13 +566,15 @@ static void as_update_iohist(struct as_data *ad, struct as_io_context *aic,
                        as_update_thinktime(ad, aic, thinktime);
 
                        /* Calculate read -> read seek distance */
-                       if (aic->last_request_pos < rq->sector)
-                               seek_dist = rq->sector - aic->last_request_pos;
+                       if (aic->last_request_pos < blk_rq_pos(rq))
+                               seek_dist = blk_rq_pos(rq) -
+                                           aic->last_request_pos;
                        else
-                               seek_dist = aic->last_request_pos - rq->sector;
+                               seek_dist = aic->last_request_pos -
+                                           blk_rq_pos(rq);
                        as_update_seekdist(ad, aic, seek_dist);
                }
-               aic->last_request_pos = rq->sector + rq->nr_sectors;
+               aic->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq);
                set_bit(AS_TASK_IOSTARTED, &aic->state);
                spin_unlock(&aic->lock);
        }
@@ -587,7 +589,7 @@ static int as_close_req(struct as_data *ad, struct as_io_context *aic,
 {
        unsigned long delay;    /* jiffies */
        sector_t last = ad->last_sector[ad->batch_data_dir];
-       sector_t next = rq->sector;
+       sector_t next = blk_rq_pos(rq);
        sector_t delta; /* acceptable close offset (in sectors) */
        sector_t s;
 
@@ -981,7 +983,7 @@ static void as_move_to_dispatch(struct as_data *ad, struct request *rq)
         * This has to be set in order to be correctly updated by
         * as_find_next_rq
         */
-       ad->last_sector[data_dir] = rq->sector + rq->nr_sectors;
+       ad->last_sector[data_dir] = blk_rq_pos(rq) + blk_rq_sectors(rq);
 
        if (data_dir == BLK_RW_SYNC) {
                struct io_context *ioc = RQ_IOC(rq);
@@ -1312,12 +1314,8 @@ static void as_merged_requests(struct request_queue *q, struct request *req,
 static void as_work_handler(struct work_struct *work)
 {
        struct as_data *ad = container_of(work, struct as_data, antic_work);
-       struct request_queue *q = ad->q;
-       unsigned long flags;
 
-       spin_lock_irqsave(q->queue_lock, flags);
-       blk_start_queueing(q);
-       spin_unlock_irqrestore(q->queue_lock, flags);
+       blk_run_queue(ad->q);
 }
 
 static int as_may_queue(struct request_queue *q, int rw)
index 20b4111fa0507a46a641faa295124afeaf5f4ea5..30022b4e2f6306b36d6c878efc0ea4abb28e5082 100644 (file)
@@ -106,10 +106,7 @@ bool blk_ordered_complete_seq(struct request_queue *q, unsigned seq, int error)
         */
        q->ordseq = 0;
        rq = q->orig_bar_rq;
-
-       if (__blk_end_request(rq, q->orderr, blk_rq_bytes(rq)))
-               BUG();
-
+       __blk_end_request_all(rq, q->orderr);
        return true;
 }
 
@@ -166,7 +163,7 @@ static inline bool start_ordered(struct request_queue *q, struct request **rqp)
         * For an empty barrier, there's no actual BAR request, which
         * in turn makes POSTFLUSH unnecessary.  Mask them off.
         */
-       if (!rq->hard_nr_sectors) {
+       if (!blk_rq_sectors(rq)) {
                q->ordered &= ~(QUEUE_ORDERED_DO_BAR |
                                QUEUE_ORDERED_DO_POSTFLUSH);
                /*
@@ -183,7 +180,7 @@ static inline bool start_ordered(struct request_queue *q, struct request **rqp)
        }
 
        /* stash away the original request */
-       elv_dequeue_request(q, rq);
+       blk_dequeue_request(rq);
        q->orig_bar_rq = rq;
        rq = NULL;
 
@@ -221,7 +218,7 @@ static inline bool start_ordered(struct request_queue *q, struct request **rqp)
        } else
                skip |= QUEUE_ORDSEQ_PREFLUSH;
 
-       if ((q->ordered & QUEUE_ORDERED_BY_DRAIN) && q->in_flight)
+       if ((q->ordered & QUEUE_ORDERED_BY_DRAIN) && queue_in_flight(q))
                rq = NULL;
        else
                skip |= QUEUE_ORDSEQ_DRAIN;
@@ -251,10 +248,8 @@ bool blk_do_ordered(struct request_queue *q, struct request **rqp)
                         * Queue ordering not supported.  Terminate
                         * with prejudice.
                         */
-                       elv_dequeue_request(q, rq);
-                       if (__blk_end_request(rq, -EOPNOTSUPP,
-                                             blk_rq_bytes(rq)))
-                               BUG();
+                       blk_dequeue_request(rq);
+                       __blk_end_request_all(rq, -EOPNOTSUPP);
                        *rqp = NULL;
                        return false;
                }
@@ -329,7 +324,7 @@ int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector)
        /*
         * The driver must store the error location in ->bi_sector, if
         * it supports it. For non-stacked drivers, this should be copied
-        * from rq->sector.
+        * from blk_rq_pos(rq).
         */
        if (error_sector)
                *error_sector = bio->bi_sector;
@@ -393,10 +388,10 @@ int blkdev_issue_discard(struct block_device *bdev,
 
                bio->bi_sector = sector;
 
-               if (nr_sects > q->max_hw_sectors) {
-                       bio->bi_size = q->max_hw_sectors << 9;
-                       nr_sects -= q->max_hw_sectors;
-                       sector += q->max_hw_sectors;
+               if (nr_sects > queue_max_hw_sectors(q)) {
+                       bio->bi_size = queue_max_hw_sectors(q) << 9;
+                       nr_sects -= queue_max_hw_sectors(q);
+                       sector += queue_max_hw_sectors(q);
                } else {
                        bio->bi_size = nr_sects << 9;
                        nr_sects = 0;
index c89883be87379d9454ab1af7cd68319e92795597..d17d71c71d4f16e1c878f97ee76218688149b1ef 100644 (file)
 #include <linux/task_io_accounting_ops.h>
 #include <linux/blktrace_api.h>
 #include <linux/fault-inject.h>
-#include <trace/block.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/block.h>
 
 #include "blk.h"
 
-DEFINE_TRACE(block_plug);
-DEFINE_TRACE(block_unplug_io);
-DEFINE_TRACE(block_unplug_timer);
-DEFINE_TRACE(block_getrq);
-DEFINE_TRACE(block_sleeprq);
-DEFINE_TRACE(block_rq_requeue);
-DEFINE_TRACE(block_bio_backmerge);
-DEFINE_TRACE(block_bio_frontmerge);
-DEFINE_TRACE(block_bio_queue);
-DEFINE_TRACE(block_rq_complete);
-DEFINE_TRACE(block_remap);     /* Also used in drivers/md/dm.c */
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_remap);
+EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete);
 
 static int __make_request(struct request_queue *q, struct bio *bio);
 
@@ -68,11 +60,11 @@ static void drive_stat_acct(struct request *rq, int new_io)
        int rw = rq_data_dir(rq);
        int cpu;
 
-       if (!blk_fs_request(rq) || !blk_do_io_stat(rq))
+       if (!blk_do_io_stat(rq))
                return;
 
        cpu = part_stat_lock();
-       part = disk_map_sector_rcu(rq->rq_disk, rq->sector);
+       part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq));
 
        if (!new_io)
                part_stat_inc(cpu, part, merges[rw]);
@@ -127,13 +119,14 @@ void blk_rq_init(struct request_queue *q, struct request *rq)
        INIT_LIST_HEAD(&rq->timeout_list);
        rq->cpu = -1;
        rq->q = q;
-       rq->sector = rq->hard_sector = (sector_t) -1;
+       rq->__sector = (sector_t) -1;
        INIT_HLIST_NODE(&rq->hash);
        RB_CLEAR_NODE(&rq->rb_node);
        rq->cmd = rq->__cmd;
        rq->cmd_len = BLK_MAX_CDB;
        rq->tag = -1;
        rq->ref_count = 1;
+       rq->start_time = jiffies;
 }
 EXPORT_SYMBOL(blk_rq_init);
 
@@ -184,14 +177,11 @@ void blk_dump_rq_flags(struct request *rq, char *msg)
                rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->cmd_type,
                rq->cmd_flags);
 
-       printk(KERN_INFO "  sector %llu, nr/cnr %lu/%u\n",
-                                               (unsigned long long)rq->sector,
-                                               rq->nr_sectors,
-                                               rq->current_nr_sectors);
-       printk(KERN_INFO "  bio %p, biotail %p, buffer %p, data %p, len %u\n",
-                                               rq->bio, rq->biotail,
-                                               rq->buffer, rq->data,
-                                               rq->data_len);
+       printk(KERN_INFO "  sector %llu, nr/cnr %u/%u\n",
+              (unsigned long long)blk_rq_pos(rq),
+              blk_rq_sectors(rq), blk_rq_cur_sectors(rq));
+       printk(KERN_INFO "  bio %p, biotail %p, buffer %p, len %u\n",
+              rq->bio, rq->biotail, rq->buffer, blk_rq_bytes(rq));
 
        if (blk_pc_request(rq)) {
                printk(KERN_INFO "  cdb: ");
@@ -333,24 +323,6 @@ void blk_unplug(struct request_queue *q)
 }
 EXPORT_SYMBOL(blk_unplug);
 
-static void blk_invoke_request_fn(struct request_queue *q)
-{
-       if (unlikely(blk_queue_stopped(q)))
-               return;
-
-       /*
-        * one level of recursion is ok and is much faster than kicking
-        * the unplug handling
-        */
-       if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) {
-               q->request_fn(q);
-               queue_flag_clear(QUEUE_FLAG_REENTER, q);
-       } else {
-               queue_flag_set(QUEUE_FLAG_PLUGGED, q);
-               kblockd_schedule_work(q, &q->unplug_work);
-       }
-}
-
 /**
  * blk_start_queue - restart a previously stopped queue
  * @q:    The &struct request_queue in question
@@ -365,7 +337,7 @@ void blk_start_queue(struct request_queue *q)
        WARN_ON(!irqs_disabled());
 
        queue_flag_clear(QUEUE_FLAG_STOPPED, q);
-       blk_invoke_request_fn(q);
+       __blk_run_queue(q);
 }
 EXPORT_SYMBOL(blk_start_queue);
 
@@ -425,12 +397,23 @@ void __blk_run_queue(struct request_queue *q)
 {
        blk_remove_plug(q);
 
+       if (unlikely(blk_queue_stopped(q)))
+               return;
+
+       if (elv_queue_empty(q))
+               return;
+
        /*
         * Only recurse once to avoid overrunning the stack, let the unplug
         * handling reinvoke the handler shortly if we already got there.
         */
-       if (!elv_queue_empty(q))
-               blk_invoke_request_fn(q);
+       if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) {
+               q->request_fn(q);
+               queue_flag_clear(QUEUE_FLAG_REENTER, q);
+       } else {
+               queue_flag_set(QUEUE_FLAG_PLUGGED, q);
+               kblockd_schedule_work(q, &q->unplug_work);
+       }
 }
 EXPORT_SYMBOL(__blk_run_queue);
 
@@ -440,9 +423,7 @@ EXPORT_SYMBOL(__blk_run_queue);
  *
  * Description:
  *    Invoke request handling on this queue, if it has pending work to do.
- *    May be used to restart queueing when a request has completed. Also
- *    See @blk_start_queueing.
- *
+ *    May be used to restart queueing when a request has completed.
  */
 void blk_run_queue(struct request_queue *q)
 {
@@ -902,26 +883,58 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask)
 EXPORT_SYMBOL(blk_get_request);
 
 /**
- * blk_start_queueing - initiate dispatch of requests to device
- * @q:         request queue to kick into gear
+ * blk_make_request - given a bio, allocate a corresponding struct request.
  *
- * This is basically a helper to remove the need to know whether a queue
- * is plugged or not if someone just wants to initiate dispatch of requests
- * for this queue. Should be used to start queueing on a device outside
- * of ->request_fn() context. Also see @blk_run_queue.
+ * @bio:  The bio describing the memory mappings that will be submitted for IO.
+ *        It may be a chained-bio properly constructed by block/bio layer.
  *
- * The queue lock must be held with interrupts disabled.
+ * blk_make_request is the parallel of generic_make_request for BLOCK_PC
+ * type commands. Where the struct request needs to be farther initialized by
+ * the caller. It is passed a &struct bio, which describes the memory info of
+ * the I/O transfer.
+ *
+ * The caller of blk_make_request must make sure that bi_io_vec
+ * are set to describe the memory buffers. That bio_data_dir() will return
+ * the needed direction of the request. (And all bio's in the passed bio-chain
+ * are properly set accordingly)
+ *
+ * If called under none-sleepable conditions, mapped bio buffers must not
+ * need bouncing, by calling the appropriate masked or flagged allocator,
+ * suitable for the target device. Otherwise the call to blk_queue_bounce will
+ * BUG.
+ *
+ * WARNING: When allocating/cloning a bio-chain, careful consideration should be
+ * given to how you allocate bios. In particular, you cannot use __GFP_WAIT for
+ * anything but the first bio in the chain. Otherwise you risk waiting for IO
+ * completion of a bio that hasn't been submitted yet, thus resulting in a
+ * deadlock. Alternatively bios should be allocated using bio_kmalloc() instead
+ * of bio_alloc(), as that avoids the mempool deadlock.
+ * If possible a big IO should be split into smaller parts when allocation
+ * fails. Partial allocation should not be an error, or you risk a live-lock.
  */
-void blk_start_queueing(struct request_queue *q)
+struct request *blk_make_request(struct request_queue *q, struct bio *bio,
+                                gfp_t gfp_mask)
 {
-       if (!blk_queue_plugged(q)) {
-               if (unlikely(blk_queue_stopped(q)))
-                       return;
-               q->request_fn(q);
-       } else
-               __generic_unplug_device(q);
+       struct request *rq = blk_get_request(q, bio_data_dir(bio), gfp_mask);
+
+       if (unlikely(!rq))
+               return ERR_PTR(-ENOMEM);
+
+       for_each_bio(bio) {
+               struct bio *bounce_bio = bio;
+               int ret;
+
+               blk_queue_bounce(q, &bounce_bio);
+               ret = blk_rq_append_bio(q, rq, bounce_bio);
+               if (unlikely(ret)) {
+                       blk_put_request(rq);
+                       return ERR_PTR(ret);
+               }
+       }
+
+       return rq;
 }
-EXPORT_SYMBOL(blk_start_queueing);
+EXPORT_SYMBOL(blk_make_request);
 
 /**
  * blk_requeue_request - put a request back on queue
@@ -942,6 +955,8 @@ void blk_requeue_request(struct request_queue *q, struct request *rq)
        if (blk_rq_tagged(rq))
                blk_queue_end_tag(q, rq);
 
+       BUG_ON(blk_queued_rq(rq));
+
        elv_requeue_request(q, rq);
 }
 EXPORT_SYMBOL(blk_requeue_request);
@@ -977,7 +992,6 @@ void blk_insert_request(struct request_queue *q, struct request *rq,
         * barrier
         */
        rq->cmd_type = REQ_TYPE_SPECIAL;
-       rq->cmd_flags |= REQ_SOFTBARRIER;
 
        rq->special = data;
 
@@ -991,7 +1005,7 @@ void blk_insert_request(struct request_queue *q, struct request *rq,
 
        drive_stat_acct(rq, 1);
        __elv_add_request(q, rq, where, 0);
-       blk_start_queueing(q);
+       __blk_run_queue(q);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 EXPORT_SYMBOL(blk_insert_request);
@@ -1113,16 +1127,13 @@ void init_request_from_bio(struct request *req, struct bio *bio)
        if (bio_failfast_driver(bio))
                req->cmd_flags |= REQ_FAILFAST_DRIVER;
 
-       /*
-        * REQ_BARRIER implies no merging, but lets make it explicit
-        */
        if (unlikely(bio_discard(bio))) {
                req->cmd_flags |= REQ_DISCARD;
                if (bio_barrier(bio))
                        req->cmd_flags |= REQ_SOFTBARRIER;
                req->q->prepare_discard_fn(req->q, req);
        } else if (unlikely(bio_barrier(bio)))
-               req->cmd_flags |= (REQ_HARDBARRIER | REQ_NOMERGE);
+               req->cmd_flags |= REQ_HARDBARRIER;
 
        if (bio_sync(bio))
                req->cmd_flags |= REQ_RW_SYNC;
@@ -1132,9 +1143,8 @@ void init_request_from_bio(struct request *req, struct bio *bio)
                req->cmd_flags |= REQ_NOIDLE;
 
        req->errors = 0;
-       req->hard_sector = req->sector = bio->bi_sector;
+       req->__sector = bio->bi_sector;
        req->ioprio = bio_prio(bio);
-       req->start_time = jiffies;
        blk_rq_bio_prep(req->q, req, bio);
 }
 
@@ -1150,14 +1160,13 @@ static inline bool queue_should_plug(struct request_queue *q)
 static int __make_request(struct request_queue *q, struct bio *bio)
 {
        struct request *req;
-       int el_ret, nr_sectors;
+       int el_ret;
+       unsigned int bytes = bio->bi_size;
        const unsigned short prio = bio_prio(bio);
        const int sync = bio_sync(bio);
        const int unplug = bio_unplug(bio);
        int rw_flags;
 
-       nr_sectors = bio_sectors(bio);
-
        /*
         * low level driver can indicate that it wants pages above a
         * certain limit bounced to low memory (ie for highmem, or even
@@ -1182,7 +1191,7 @@ static int __make_request(struct request_queue *q, struct bio *bio)
 
                req->biotail->bi_next = bio;
                req->biotail = bio;
-               req->nr_sectors = req->hard_nr_sectors += nr_sectors;
+               req->__data_len += bytes;
                req->ioprio = ioprio_best(req->ioprio, prio);
                if (!blk_rq_cpu_valid(req))
                        req->cpu = bio->bi_comp_cpu;
@@ -1208,10 +1217,8 @@ static int __make_request(struct request_queue *q, struct bio *bio)
                 * not touch req->buffer either...
                 */
                req->buffer = bio_data(bio);
-               req->current_nr_sectors = bio_cur_sectors(bio);
-               req->hard_cur_sectors = req->current_nr_sectors;
-               req->sector = req->hard_sector = bio->bi_sector;
-               req->nr_sectors = req->hard_nr_sectors += nr_sectors;
+               req->__sector = bio->bi_sector;
+               req->__data_len += bytes;
                req->ioprio = ioprio_best(req->ioprio, prio);
                if (!blk_rq_cpu_valid(req))
                        req->cpu = bio->bi_comp_cpu;
@@ -1277,7 +1284,7 @@ static inline void blk_partition_remap(struct bio *bio)
                bio->bi_bdev = bdev->bd_contains;
 
                trace_block_remap(bdev_get_queue(bio->bi_bdev), bio,
-                                   bdev->bd_dev, bio->bi_sector,
+                                   bdev->bd_dev,
                                    bio->bi_sector - p->start_sect);
        }
 }
@@ -1422,11 +1429,11 @@ static inline void __generic_make_request(struct bio *bio)
                        goto end_io;
                }
 
-               if (unlikely(nr_sectors > q->max_hw_sectors)) {
+               if (unlikely(nr_sectors > queue_max_hw_sectors(q))) {
                        printk(KERN_ERR "bio too big device %s (%u > %u)\n",
-                               bdevname(bio->bi_bdev, b),
-                               bio_sectors(bio),
-                               q->max_hw_sectors);
+                              bdevname(bio->bi_bdev, b),
+                              bio_sectors(bio),
+                              queue_max_hw_sectors(q));
                        goto end_io;
                }
 
@@ -1446,8 +1453,7 @@ static inline void __generic_make_request(struct bio *bio)
                        goto end_io;
 
                if (old_sector != -1)
-                       trace_block_remap(q, bio, old_dev, bio->bi_sector,
-                                           old_sector);
+                       trace_block_remap(q, bio, old_dev, old_sector);
 
                trace_block_bio_queue(q, bio);
 
@@ -1593,8 +1599,8 @@ EXPORT_SYMBOL(submit_bio);
  */
 int blk_rq_check_limits(struct request_queue *q, struct request *rq)
 {
-       if (rq->nr_sectors > q->max_sectors ||
-           rq->data_len > q->max_hw_sectors << 9) {
+       if (blk_rq_sectors(rq) > queue_max_sectors(q) ||
+           blk_rq_bytes(rq) > queue_max_hw_sectors(q) << 9) {
                printk(KERN_ERR "%s: over max size limit.\n", __func__);
                return -EIO;
        }
@@ -1606,8 +1612,8 @@ int blk_rq_check_limits(struct request_queue *q, struct request *rq)
         * limitation.
         */
        blk_recalc_rq_segments(rq);
-       if (rq->nr_phys_segments > q->max_phys_segments ||
-           rq->nr_phys_segments > q->max_hw_segments) {
+       if (rq->nr_phys_segments > queue_max_phys_segments(q) ||
+           rq->nr_phys_segments > queue_max_hw_segments(q)) {
                printk(KERN_ERR "%s: over max segments limit.\n", __func__);
                return -EIO;
        }
@@ -1651,40 +1657,15 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
 }
 EXPORT_SYMBOL_GPL(blk_insert_cloned_request);
 
-/**
- * blkdev_dequeue_request - dequeue request and start timeout timer
- * @req: request to dequeue
- *
- * Dequeue @req and start timeout timer on it.  This hands off the
- * request to the driver.
- *
- * Block internal functions which don't want to start timer should
- * call elv_dequeue_request().
- */
-void blkdev_dequeue_request(struct request *req)
-{
-       elv_dequeue_request(req->q, req);
-
-       /*
-        * We are now handing the request to the hardware, add the
-        * timeout handler.
-        */
-       blk_add_timer(req);
-}
-EXPORT_SYMBOL(blkdev_dequeue_request);
-
 static void blk_account_io_completion(struct request *req, unsigned int bytes)
 {
-       if (!blk_do_io_stat(req))
-               return;
-
-       if (blk_fs_request(req)) {
+       if (blk_do_io_stat(req)) {
                const int rw = rq_data_dir(req);
                struct hd_struct *part;
                int cpu;
 
                cpu = part_stat_lock();
-               part = disk_map_sector_rcu(req->rq_disk, req->sector);
+               part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
                part_stat_add(cpu, part, sectors[rw], bytes >> 9);
                part_stat_unlock();
        }
@@ -1692,22 +1673,19 @@ static void blk_account_io_completion(struct request *req, unsigned int bytes)
 
 static void blk_account_io_done(struct request *req)
 {
-       if (!blk_do_io_stat(req))
-               return;
-
        /*
         * Account IO completion.  bar_rq isn't accounted as a normal
         * IO on queueing nor completion.  Accounting the containing
         * request is enough.
         */
-       if (blk_fs_request(req) && req != &req->q->bar_rq) {
+       if (blk_do_io_stat(req) && req != &req->q->bar_rq) {
                unsigned long duration = jiffies - req->start_time;
                const int rw = rq_data_dir(req);
                struct hd_struct *part;
                int cpu;
 
                cpu = part_stat_lock();
-               part = disk_map_sector_rcu(req->rq_disk, req->sector);
+               part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
 
                part_stat_inc(cpu, part, ios[rw]);
                part_stat_add(cpu, part, ticks[rw], duration);
@@ -1719,38 +1697,226 @@ static void blk_account_io_done(struct request *req)
 }
 
 /**
- * __end_that_request_first - end I/O on a request
- * @req:      the request being processed
+ * blk_peek_request - peek at the top of a request queue
+ * @q: request queue to peek at
+ *
+ * Description:
+ *     Return the request at the top of @q.  The returned request
+ *     should be started using blk_start_request() before LLD starts
+ *     processing it.
+ *
+ * Return:
+ *     Pointer to the request at the top of @q if available.  Null
+ *     otherwise.
+ *
+ * Context:
+ *     queue_lock must be held.
+ */
+struct request *blk_peek_request(struct request_queue *q)
+{
+       struct request *rq;
+       int ret;
+
+       while ((rq = __elv_next_request(q)) != NULL) {
+               if (!(rq->cmd_flags & REQ_STARTED)) {
+                       /*
+                        * This is the first time the device driver
+                        * sees this request (possibly after
+                        * requeueing).  Notify IO scheduler.
+                        */
+                       if (blk_sorted_rq(rq))
+                               elv_activate_rq(q, rq);
+
+                       /*
+                        * just mark as started even if we don't start
+                        * it, a request that has been delayed should
+                        * not be passed by new incoming requests
+                        */
+                       rq->cmd_flags |= REQ_STARTED;
+                       trace_block_rq_issue(q, rq);
+               }
+
+               if (!q->boundary_rq || q->boundary_rq == rq) {
+                       q->end_sector = rq_end_sector(rq);
+                       q->boundary_rq = NULL;
+               }
+
+               if (rq->cmd_flags & REQ_DONTPREP)
+                       break;
+
+               if (q->dma_drain_size && blk_rq_bytes(rq)) {
+                       /*
+                        * make sure space for the drain appears we
+                        * know we can do this because max_hw_segments
+                        * has been adjusted to be one fewer than the
+                        * device can handle
+                        */
+                       rq->nr_phys_segments++;
+               }
+
+               if (!q->prep_rq_fn)
+                       break;
+
+               ret = q->prep_rq_fn(q, rq);
+               if (ret == BLKPREP_OK) {
+                       break;
+               } else if (ret == BLKPREP_DEFER) {
+                       /*
+                        * the request may have been (partially) prepped.
+                        * we need to keep this request in the front to
+                        * avoid resource deadlock.  REQ_STARTED will
+                        * prevent other fs requests from passing this one.
+                        */
+                       if (q->dma_drain_size && blk_rq_bytes(rq) &&
+                           !(rq->cmd_flags & REQ_DONTPREP)) {
+                               /*
+                                * remove the space for the drain we added
+                                * so that we don't add it again
+                                */
+                               --rq->nr_phys_segments;
+                       }
+
+                       rq = NULL;
+                       break;
+               } else if (ret == BLKPREP_KILL) {
+                       rq->cmd_flags |= REQ_QUIET;
+                       /*
+                        * Mark this request as started so we don't trigger
+                        * any debug logic in the end I/O path.
+                        */
+                       blk_start_request(rq);
+                       __blk_end_request_all(rq, -EIO);
+               } else {
+                       printk(KERN_ERR "%s: bad return=%d\n", __func__, ret);
+                       break;
+               }
+       }
+
+       return rq;
+}
+EXPORT_SYMBOL(blk_peek_request);
+
+void blk_dequeue_request(struct request *rq)
+{
+       struct request_queue *q = rq->q;
+
+       BUG_ON(list_empty(&rq->queuelist));
+       BUG_ON(ELV_ON_HASH(rq));
+
+       list_del_init(&rq->queuelist);
+
+       /*
+        * the time frame between a request being removed from the lists
+        * and to it is freed is accounted as io that is in progress at
+        * the driver side.
+        */
+       if (blk_account_rq(rq))
+               q->in_flight[rq_is_sync(rq)]++;
+}
+
+/**
+ * blk_start_request - start request processing on the driver
+ * @req: request to dequeue
+ *
+ * Description:
+ *     Dequeue @req and start timeout timer on it.  This hands off the
+ *     request to the driver.
+ *
+ *     Block internal functions which don't want to start timer should
+ *     call blk_dequeue_request().
+ *
+ * Context:
+ *     queue_lock must be held.
+ */
+void blk_start_request(struct request *req)
+{
+       blk_dequeue_request(req);
+
+       /*
+        * We are now handing the request to the hardware, initialize
+        * resid_len to full count and add the timeout handler.
+        */
+       req->resid_len = blk_rq_bytes(req);
+       if (unlikely(blk_bidi_rq(req)))
+               req->next_rq->resid_len = blk_rq_bytes(req->next_rq);
+
+       blk_add_timer(req);
+}
+EXPORT_SYMBOL(blk_start_request);
+
+/**
+ * blk_fetch_request - fetch a request from a request queue
+ * @q: request queue to fetch a request from
+ *
+ * Description:
+ *     Return the request at the top of @q.  The request is started on
+ *     return and LLD can start processing it immediately.
+ *
+ * Return:
+ *     Pointer to the request at the top of @q if available.  Null
+ *     otherwise.
+ *
+ * Context:
+ *     queue_lock must be held.
+ */
+struct request *blk_fetch_request(struct request_queue *q)
+{
+       struct request *rq;
+
+       rq = blk_peek_request(q);
+       if (rq)
+               blk_start_request(rq);
+       return rq;
+}
+EXPORT_SYMBOL(blk_fetch_request);
+
+/**
+ * blk_update_request - Special helper function for request stacking drivers
+ * @rq:              the request being processed
  * @error:    %0 for success, < %0 for error
- * @nr_bytes: number of bytes to complete
+ * @nr_bytes: number of bytes to complete @rq
  *
  * Description:
- *     Ends I/O on a number of bytes attached to @req, and sets it up
- *     for the next range of segments (if any) in the cluster.
+ *     Ends I/O on a number of bytes attached to @rq, but doesn't complete
+ *     the request structure even if @rq doesn't have leftover.
+ *     If @rq has leftover, sets it up for the next range of segments.
+ *
+ *     This special helper function is only for request stacking drivers
+ *     (e.g. request-based dm) so that they can handle partial completion.
+ *     Actual device drivers should use blk_end_request instead.
+ *
+ *     Passing the result of blk_rq_bytes() as @nr_bytes guarantees
+ *     %false return from this function.
  *
  * Return:
- *     %0 - we are done with this request, call end_that_request_last()
- *     %1 - still buffers pending for this request
+ *     %false - this request doesn't have any more data
+ *     %true  - this request has more data
  **/
-static int __end_that_request_first(struct request *req, int error,
-                                   int nr_bytes)
+bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
 {
        int total_bytes, bio_nbytes, next_idx = 0;
        struct bio *bio;
 
+       if (!req->bio)
+               return false;
+
        trace_block_rq_complete(req->q, req);
 
        /*
-        * for a REQ_TYPE_BLOCK_PC request, we want to carry any eventual
-        * sense key with us all the way through
+        * For fs requests, rq is just carrier of independent bio's
+        * and each partial completion should be handled separately.
+        * Reset per-request error on each partial completion.
+        *
+        * TODO: tj: This is too subtle.  It would be better to let
+        * low level drivers do what they see fit.
         */
-       if (!blk_pc_request(req))
+       if (blk_fs_request(req))
                req->errors = 0;
 
        if (error && (blk_fs_request(req) && !(req->cmd_flags & REQ_QUIET))) {
                printk(KERN_ERR "end_request: I/O error, dev %s, sector %llu\n",
                                req->rq_disk ? req->rq_disk->disk_name : "?",
-                               (unsigned long long)req->sector);
+                               (unsigned long long)blk_rq_pos(req));
        }
 
        blk_account_io_completion(req, nr_bytes);
@@ -1810,8 +1976,15 @@ static int __end_that_request_first(struct request *req, int error,
        /*
         * completely done
         */
-       if (!req->bio)
-               return 0;
+       if (!req->bio) {
+               /*
+                * Reset counters so that the request stacking driver
+                * can find how many bytes remain in the request
+                * later.
+                */
+               req->__data_len = 0;
+               return false;
+       }
 
        /*
         * if the request wasn't completed, update state
@@ -1823,21 +1996,55 @@ static int __end_that_request_first(struct request *req, int error,
                bio_iovec(bio)->bv_len -= nr_bytes;
        }
 
-       blk_recalc_rq_sectors(req, total_bytes >> 9);
+       req->__data_len -= total_bytes;
+       req->buffer = bio_data(req->bio);
+
+       /* update sector only for requests with clear definition of sector */
+       if (blk_fs_request(req) || blk_discard_rq(req))
+               req->__sector += total_bytes >> 9;
+
+       /*
+        * If total number of sectors is less than the first segment
+        * size, something has gone terribly wrong.
+        */
+       if (blk_rq_bytes(req) < blk_rq_cur_bytes(req)) {
+               printk(KERN_ERR "blk: request botched\n");
+               req->__data_len = blk_rq_cur_bytes(req);
+       }
+
+       /* recalculate the number of segments */
        blk_recalc_rq_segments(req);
-       return 1;
+
+       return true;
+}
+EXPORT_SYMBOL_GPL(blk_update_request);
+
+static bool blk_update_bidi_request(struct request *rq, int error,
+                                   unsigned int nr_bytes,
+                                   unsigned int bidi_bytes)
+{
+       if (blk_update_request(rq, error, nr_bytes))
+               return true;
+
+       /* Bidi request must be completed as a whole */
+       if (unlikely(blk_bidi_rq(rq)) &&
+           blk_update_request(rq->next_rq, error, bidi_bytes))
+               return true;
+
+       add_disk_randomness(rq->rq_disk);
+
+       return false;
 }
 
 /*
  * queue lock must be held
  */
-static void end_that_request_last(struct request *req, int error)
+static void blk_finish_request(struct request *req, int error)
 {
        if (blk_rq_tagged(req))
                blk_queue_end_tag(req->q, req);
 
-       if (blk_queued_rq(req))
-               elv_dequeue_request(req->q, req);
+       BUG_ON(blk_queued_rq(req));
 
        if (unlikely(laptop_mode) && blk_fs_request(req))
                laptop_io_completion();
@@ -1857,117 +2064,62 @@ static void end_that_request_last(struct request *req, int error)
 }
 
 /**
- * blk_rq_bytes - Returns bytes left to complete in the entire request
- * @rq: the request being processed
- **/
-unsigned int blk_rq_bytes(struct request *rq)
-{
-       if (blk_fs_request(rq))
-               return rq->hard_nr_sectors << 9;
-
-       return rq->data_len;
-}
-EXPORT_SYMBOL_GPL(blk_rq_bytes);
-
-/**
- * blk_rq_cur_bytes - Returns bytes left to complete in the current segment
- * @rq: the request being processed
- **/
-unsigned int blk_rq_cur_bytes(struct request *rq)
-{
-       if (blk_fs_request(rq))
-               return rq->current_nr_sectors << 9;
-
-       if (rq->bio)
-               return rq->bio->bi_size;
-
-       return rq->data_len;
-}
-EXPORT_SYMBOL_GPL(blk_rq_cur_bytes);
-
-/**
- * end_request - end I/O on the current segment of the request
- * @req:       the request being processed
- * @uptodate:  error value or %0/%1 uptodate flag
+ * blk_end_bidi_request - Complete a bidi request
+ * @rq:         the request to complete
+ * @error:      %0 for success, < %0 for error
+ * @nr_bytes:   number of bytes to complete @rq
+ * @bidi_bytes: number of bytes to complete @rq->next_rq
  *
  * Description:
- *     Ends I/O on the current segment of a request. If that is the only
- *     remaining segment, the request is also completed and freed.
- *
- *     This is a remnant of how older block drivers handled I/O completions.
- *     Modern drivers typically end I/O on the full request in one go, unless
- *     they have a residual value to account for. For that case this function
- *     isn't really useful, unless the residual just happens to be the
- *     full current segment. In other words, don't use this function in new
- *     code. Use blk_end_request() or __blk_end_request() to end a request.
+ *     Ends I/O on a number of bytes attached to @rq and @rq->next_rq.
+ *     Drivers that supports bidi can safely call this member for any
+ *     type of request, bidi or uni.  In the later case @bidi_bytes is
+ *     just ignored.
+ *
+ * Return:
+ *     %false - we are done with this request
+ *     %true  - still buffers pending for this request
  **/
-void end_request(struct request *req, int uptodate)
-{
-       int error = 0;
-
-       if (uptodate <= 0)
-               error = uptodate ? uptodate : -EIO;
-
-       __blk_end_request(req, error, req->hard_cur_sectors << 9);
-}
-EXPORT_SYMBOL(end_request);
-
-static int end_that_request_data(struct request *rq, int error,
+static bool blk_end_bidi_request(struct request *rq, int error,
                                 unsigned int nr_bytes, unsigned int bidi_bytes)
 {
-       if (rq->bio) {
-               if (__end_that_request_first(rq, error, nr_bytes))
-                       return 1;
+       struct request_queue *q = rq->q;
+       unsigned long flags;
 
-               /* Bidi request must be completed as a whole */
-               if (blk_bidi_rq(rq) &&
-                   __end_that_request_first(rq->next_rq, error, bidi_bytes))
-                       return 1;
-       }
+       if (blk_update_bidi_request(rq, error, nr_bytes, bidi_bytes))
+               return true;
 
-       return 0;
+       spin_lock_irqsave(q->queue_lock, flags);
+       blk_finish_request(rq, error);
+       spin_unlock_irqrestore(q->queue_lock, flags);
+
+       return false;
 }
 
 /**
- * blk_end_io - Generic end_io function to complete a request.
- * @rq:           the request being processed
- * @error:        %0 for success, < %0 for error
- * @nr_bytes:     number of bytes to complete @rq
- * @bidi_bytes:   number of bytes to complete @rq->next_rq
- * @drv_callback: function called between completion of bios in the request
- *                and completion of the request.
- *                If the callback returns non %0, this helper returns without
- *                completion of the request.
+ * __blk_end_bidi_request - Complete a bidi request with queue lock held
+ * @rq:         the request to complete
+ * @error:      %0 for success, < %0 for error
+ * @nr_bytes:   number of bytes to complete @rq
+ * @bidi_bytes: number of bytes to complete @rq->next_rq
  *
  * Description:
- *     Ends I/O on a number of bytes attached to @rq and @rq->next_rq.
- *     If @rq has leftover, sets it up for the next range of segments.
+ *     Identical to blk_end_bidi_request() except that queue lock is
+ *     assumed to be locked on entry and remains so on return.
  *
  * Return:
- *     %0 - we are done with this request
- *     %1 - this request is not freed yet, it still has pending buffers.
+ *     %false - we are done with this request
+ *     %true  - still buffers pending for this request
  **/
-static int blk_end_io(struct request *rq, int error, unsigned int nr_bytes,
-                     unsigned int bidi_bytes,
-                     int (drv_callback)(struct request *))
+static bool __blk_end_bidi_request(struct request *rq, int error,
+                                  unsigned int nr_bytes, unsigned int bidi_bytes)
 {
-       struct request_queue *q = rq->q;
-       unsigned long flags = 0UL;
-
-       if (end_that_request_data(rq, error, nr_bytes, bidi_bytes))
-               return 1;
-
-       /* Special feature for tricky drivers */
-       if (drv_callback && drv_callback(rq))
-               return 1;
+       if (blk_update_bidi_request(rq, error, nr_bytes, bidi_bytes))
+               return true;
 
-       add_disk_randomness(rq->rq_disk);
+       blk_finish_request(rq, error);
 
-       spin_lock_irqsave(q->queue_lock, flags);
-       end_that_request_last(rq, error);
-       spin_unlock_irqrestore(q->queue_lock, flags);
-
-       return 0;
+       return false;
 }
 
 /**
@@ -1981,124 +2133,112 @@ static int blk_end_io(struct request *rq, int error, unsigned int nr_bytes,
  *     If @rq has leftover, sets it up for the next range of segments.
  *
  * Return:
- *     %0 - we are done with this request
- *     %1 - still buffers pending for this request
+ *     %false - we are done with this request
+ *     %true  - still buffers pending for this request
  **/
-int blk_end_request(struct request *rq, int error, unsigned int nr_bytes)
+bool blk_end_request(struct request *rq, int error, unsigned int nr_bytes)
 {
-       return blk_end_io(rq, error, nr_bytes, 0, NULL);
+       return blk_end_bidi_request(rq, error, nr_bytes, 0);
 }
 EXPORT_SYMBOL_GPL(blk_end_request);
 
 /**
- * __blk_end_request - Helper function for drivers to complete the request.
- * @rq:       the request being processed
- * @error:    %0 for success, < %0 for error
- * @nr_bytes: number of bytes to complete
+ * blk_end_request_all - Helper function for drives to finish the request.
+ * @rq: the request to finish
+ * @err: %0 for success, < %0 for error
  *
  * Description:
- *     Must be called with queue lock held unlike blk_end_request().
- *
- * Return:
- *     %0 - we are done with this request
- *     %1 - still buffers pending for this request
- **/
-int __blk_end_request(struct request *rq, int error, unsigned int nr_bytes)
+ *     Completely finish @rq.
+ */
+void blk_end_request_all(struct request *rq, int error)
 {
-       if (rq->bio && __end_that_request_first(rq, error, nr_bytes))
-               return 1;
+       bool pending;
+       unsigned int bidi_bytes = 0;
 
-       add_disk_randomness(rq->rq_disk);
+       if (unlikely(blk_bidi_rq(rq)))
+               bidi_bytes = blk_rq_bytes(rq->next_rq);
 
-       end_that_request_last(rq, error);
+       pending = blk_end_bidi_request(rq, error, blk_rq_bytes(rq), bidi_bytes);
+       BUG_ON(pending);
+}
+EXPORT_SYMBOL_GPL(blk_end_request_all);
 
-       return 0;
+/**
+ * blk_end_request_cur - Helper function to finish the current request chunk.
+ * @rq: the request to finish the current chunk for
+ * @err: %0 for success, < %0 for error
+ *
+ * Description:
+ *     Complete the current consecutively mapped chunk from @rq.
+ *
+ * Return:
+ *     %false - we are done with this request
+ *     %true  - still buffers pending for this request
+ */
+bool blk_end_request_cur(struct request *rq, int error)
+{
+       return blk_end_request(rq, error, blk_rq_cur_bytes(rq));
 }
-EXPORT_SYMBOL_GPL(__blk_end_request);
+EXPORT_SYMBOL_GPL(blk_end_request_cur);
 
 /**
- * blk_end_bidi_request - Helper function for drivers to complete bidi request.
- * @rq:         the bidi request being processed
- * @error:      %0 for success, < %0 for error
- * @nr_bytes:   number of bytes to complete @rq
- * @bidi_bytes: number of bytes to complete @rq->next_rq
+ * __blk_end_request - Helper function for drivers to complete the request.
+ * @rq:       the request being processed
+ * @error:    %0 for success, < %0 for error
+ * @nr_bytes: number of bytes to complete
  *
  * Description:
- *     Ends I/O on a number of bytes attached to @rq and @rq->next_rq.
+ *     Must be called with queue lock held unlike blk_end_request().
  *
  * Return:
- *     %0 - we are done with this request
- *     %1 - still buffers pending for this request
+ *     %false - we are done with this request
+ *     %true  - still buffers pending for this request
  **/
-int blk_end_bidi_request(struct request *rq, int error, unsigned int nr_bytes,
-                        unsigned int bidi_bytes)
+bool __blk_end_request(struct request *rq, int error, unsigned int nr_bytes)
 {
-       return blk_end_io(rq, error, nr_bytes, bidi_bytes, NULL);
+       return __blk_end_bidi_request(rq, error, nr_bytes, 0);
 }
-EXPORT_SYMBOL_GPL(blk_end_bidi_request);
+EXPORT_SYMBOL_GPL(__blk_end_request);
 
 /**
- * blk_update_request - Special helper function for request stacking drivers
- * @rq:           the request being processed
- * @error:        %0 for success, < %0 for error
- * @nr_bytes:     number of bytes to complete @rq
+ * __blk_end_request_all - Helper function for drives to finish the request.
+ * @rq: the request to finish
+ * @err: %0 for success, < %0 for error
  *
  * Description:
- *     Ends I/O on a number of bytes attached to @rq, but doesn't complete
- *     the request structure even if @rq doesn't have leftover.
- *     If @rq has leftover, sets it up for the next range of segments.
- *
- *     This special helper function is only for request stacking drivers
- *     (e.g. request-based dm) so that they can handle partial completion.
- *     Actual device drivers should use blk_end_request instead.
+ *     Completely finish @rq.  Must be called with queue lock held.
  */
-void blk_update_request(struct request *rq, int error, unsigned int nr_bytes)
+void __blk_end_request_all(struct request *rq, int error)
 {
-       if (!end_that_request_data(rq, error, nr_bytes, 0)) {
-               /*
-                * These members are not updated in end_that_request_data()
-                * when all bios are completed.
-                * Update them so that the request stacking driver can find
-                * how many bytes remain in the request later.
-                */
-               rq->nr_sectors = rq->hard_nr_sectors = 0;
-               rq->current_nr_sectors = rq->hard_cur_sectors = 0;
-       }
+       bool pending;
+       unsigned int bidi_bytes = 0;
+
+       if (unlikely(blk_bidi_rq(rq)))
+               bidi_bytes = blk_rq_bytes(rq->next_rq);
+
+       pending = __blk_end_bidi_request(rq, error, blk_rq_bytes(rq), bidi_bytes);
+       BUG_ON(pending);
 }
-EXPORT_SYMBOL_GPL(blk_update_request);
+EXPORT_SYMBOL_GPL(__blk_end_request_all);
 
 /**
- * blk_end_request_callback - Special helper function for tricky drivers
- * @rq:           the request being processed
- * @error:        %0 for success, < %0 for error
- * @nr_bytes:     number of bytes to complete
- * @drv_callback: function called between completion of bios in the request
- *                and completion of the request.
- *                If the callback returns non %0, this helper returns without
- *                completion of the request.
+ * __blk_end_request_cur - Helper function to finish the current request chunk.
+ * @rq: the request to finish the current chunk for
+ * @err: %0 for success, < %0 for error
  *
  * Description:
- *     Ends I/O on a number of bytes attached to @rq.
- *     If @rq has leftover, sets it up for the next range of segments.
- *
- *     This special helper function is used only for existing tricky drivers.
- *     (e.g. cdrom_newpc_intr() of ide-cd)
- *     This interface will be removed when such drivers are rewritten.
- *     Don't use this interface in other places anymore.
+ *     Complete the current consecutively mapped chunk from @rq.  Must
+ *     be called with queue lock held.
  *
  * Return:
- *     %0 - we are done with this request
- *     %1 - this request is not freed yet.
- *          this request still has pending buffers or
- *          the driver doesn't want to finish this request yet.
- **/
-int blk_end_request_callback(struct request *rq, int error,
-                            unsigned int nr_bytes,
-                            int (drv_callback)(struct request *))
+ *     %false - we are done with this request
+ *     %true  - still buffers pending for this request
+ */
+bool __blk_end_request_cur(struct request *rq, int error)
 {
-       return blk_end_io(rq, error, nr_bytes, 0, drv_callback);
+       return __blk_end_request(rq, error, blk_rq_cur_bytes(rq));
 }
-EXPORT_SYMBOL_GPL(blk_end_request_callback);
+EXPORT_SYMBOL_GPL(__blk_end_request_cur);
 
 void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
                     struct bio *bio)
@@ -2111,11 +2251,7 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
                rq->nr_phys_segments = bio_phys_segments(q, bio);
                rq->buffer = bio_data(bio);
        }
-       rq->current_nr_sectors = bio_cur_sectors(bio);
-       rq->hard_cur_sectors = rq->current_nr_sectors;
-       rq->hard_nr_sectors = rq->nr_sectors = bio_sectors(bio);
-       rq->data_len = bio->bi_size;
-
+       rq->__data_len = bio->bi_size;
        rq->bio = rq->biotail = bio;
 
        if (bio->bi_bdev)
@@ -2150,6 +2286,106 @@ int blk_lld_busy(struct request_queue *q)
 }
 EXPORT_SYMBOL_GPL(blk_lld_busy);
 
+/**
+ * blk_rq_unprep_clone - Helper function to free all bios in a cloned request
+ * @rq: the clone request to be cleaned up
+ *
+ * Description:
+ *     Free all bios in @rq for a cloned request.
+ */
+void blk_rq_unprep_clone(struct request *rq)
+{
+       struct bio *bio;
+
+       while ((bio = rq->bio) != NULL) {
+               rq->bio = bio->bi_next;
+
+               bio_put(bio);
+       }
+}
+EXPORT_SYMBOL_GPL(blk_rq_unprep_clone);
+
+/*
+ * Copy attributes of the original request to the clone request.
+ * The actual data parts (e.g. ->cmd, ->buffer, ->sense) are not copied.
+ */
+static void __blk_rq_prep_clone(struct request *dst, struct request *src)
+{
+       dst->cpu = src->cpu;
+       dst->cmd_flags = (rq_data_dir(src) | REQ_NOMERGE);
+       dst->cmd_type = src->cmd_type;
+       dst->__sector = blk_rq_pos(src);
+       dst->__data_len = blk_rq_bytes(src);
+       dst->nr_phys_segments = src->nr_phys_segments;
+       dst->ioprio = src->ioprio;
+       dst->extra_len = src->extra_len;
+}
+
+/**
+ * blk_rq_prep_clone - Helper function to setup clone request
+ * @rq: the request to be setup
+ * @rq_src: original request to be cloned
+ * @bs: bio_set that bios for clone are allocated from
+ * @gfp_mask: memory allocation mask for bio
+ * @bio_ctr: setup function to be called for each clone bio.
+ *           Returns %0 for success, non %0 for failure.
+ * @data: private data to be passed to @bio_ctr
+ *
+ * Description:
+ *     Clones bios in @rq_src to @rq, and copies attributes of @rq_src to @rq.
+ *     The actual data parts of @rq_src (e.g. ->cmd, ->buffer, ->sense)
+ *     are not copied, and copying such parts is the caller's responsibility.
+ *     Also, pages which the original bios are pointing to are not copied
+ *     and the cloned bios just point same pages.
+ *     So cloned bios must be completed before original bios, which means
+ *     the caller must complete @rq before @rq_src.
+ */
+int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
+                     struct bio_set *bs, gfp_t gfp_mask,
+                     int (*bio_ctr)(struct bio *, struct bio *, void *),
+                     void *data)
+{
+       struct bio *bio, *bio_src;
+
+       if (!bs)
+               bs = fs_bio_set;
+
+       blk_rq_init(NULL, rq);
+
+       __rq_for_each_bio(bio_src, rq_src) {
+               bio = bio_alloc_bioset(gfp_mask, bio_src->bi_max_vecs, bs);
+               if (!bio)
+                       goto free_and_out;
+
+               __bio_clone(bio, bio_src);
+
+               if (bio_integrity(bio_src) &&
+                   bio_integrity_clone(bio, bio_src, gfp_mask))
+                       goto free_and_out;
+
+               if (bio_ctr && bio_ctr(bio, bio_src, data))
+                       goto free_and_out;
+
+               if (rq->bio) {
+                       rq->biotail->bi_next = bio;
+                       rq->biotail = bio;
+               } else
+                       rq->bio = rq->biotail = bio;
+       }
+
+       __blk_rq_prep_clone(rq, rq_src);
+
+       return 0;
+
+free_and_out:
+       if (bio)
+               bio_free(bio, bs);
+       blk_rq_unprep_clone(rq);
+
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(blk_rq_prep_clone);
+
 int kblockd_schedule_work(struct request_queue *q, struct work_struct *work)
 {
        return queue_work(kblockd_workqueue, work);
@@ -2158,6 +2394,9 @@ EXPORT_SYMBOL(kblockd_schedule_work);
 
 int __init blk_dev_init(void)
 {
+       BUILD_BUG_ON(__REQ_NR_BITS > 8 *
+                       sizeof(((struct request *)0)->cmd_flags));
+
        kblockd_workqueue = create_workqueue("kblockd");
        if (!kblockd_workqueue)
                panic("Failed to create kblockd\n");
index 6af716d1e54e038468c455e093f2d1e08719812e..49557e91f0dab58cda736b556378525dbea497b8 100644 (file)
@@ -51,7 +51,6 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
        int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;
 
        rq->rq_disk = bd_disk;
-       rq->cmd_flags |= REQ_NOMERGE;
        rq->end_io = done;
        WARN_ON(irqs_disabled());
        spin_lock_irq(q->queue_lock);
index 91fa8e06b6a57712d716f1c3e9becd2c5118fc1a..73e28d35568841e5caebd9b8b0648c5b21bee0b4 100644 (file)
@@ -340,7 +340,7 @@ int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
                kobject_uevent(&bi->kobj, KOBJ_ADD);
 
                bi->flags |= INTEGRITY_FLAG_READ | INTEGRITY_FLAG_WRITE;
-               bi->sector_size = disk->queue->hardsect_size;
+               bi->sector_size = queue_logical_block_size(disk->queue);
                disk->integrity = bi;
        } else
                bi = disk->integrity;
index 012f065ac8e248d4e42485a7ef9a728692bb43a1..d4ed6000147d11221c72cc45322d4c6ea6c68d74 100644 (file)
@@ -35,9 +35,9 @@ int put_io_context(struct io_context *ioc)
        if (ioc == NULL)
                return 1;
 
-       BUG_ON(atomic_read(&ioc->refcount) == 0);
+       BUG_ON(atomic_long_read(&ioc->refcount) == 0);
 
-       if (atomic_dec_and_test(&ioc->refcount)) {
+       if (atomic_long_dec_and_test(&ioc->refcount)) {
                rcu_read_lock();
                if (ioc->aic && ioc->aic->dtor)
                        ioc->aic->dtor(ioc->aic);
@@ -90,7 +90,7 @@ struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
 
        ret = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node);
        if (ret) {
-               atomic_set(&ret->refcount, 1);
+               atomic_long_set(&ret->refcount, 1);
                atomic_set(&ret->nr_tasks, 1);
                spin_lock_init(&ret->lock);
                ret->ioprio_changed = 0;
@@ -151,7 +151,7 @@ struct io_context *get_io_context(gfp_t gfp_flags, int node)
                ret = current_io_context(gfp_flags, node);
                if (unlikely(!ret))
                        break;
-       } while (!atomic_inc_not_zero(&ret->refcount));
+       } while (!atomic_long_inc_not_zero(&ret->refcount));
 
        return ret;
 }
@@ -163,8 +163,8 @@ void copy_io_context(struct io_context **pdst, struct io_context **psrc)
        struct io_context *dst = *pdst;
 
        if (src) {
-               BUG_ON(atomic_read(&src->refcount) == 0);
-               atomic_inc(&src->refcount);
+               BUG_ON(atomic_long_read(&src->refcount) == 0);
+               atomic_long_inc(&src->refcount);
                put_io_context(dst);
                *pdst = src;
        }
index f103729b462fdb817d3a51caf5cf33984d0e6cf6..9083cf0180cc8a296d2529a4ef9d9943ea5d05c1 100644 (file)
@@ -20,11 +20,10 @@ int blk_rq_append_bio(struct request_queue *q, struct request *rq,
                rq->biotail->bi_next = bio;
                rq->biotail = bio;
 
-               rq->data_len += bio->bi_size;
+               rq->__data_len += bio->bi_size;
        }
        return 0;
 }
-EXPORT_SYMBOL(blk_rq_append_bio);
 
 static int __blk_rq_unmap_user(struct bio *bio)
 {
@@ -116,7 +115,7 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq,
        struct bio *bio = NULL;
        int ret;
 
-       if (len > (q->max_hw_sectors << 9))
+       if (len > (queue_max_hw_sectors(q) << 9))
                return -EINVAL;
        if (!len)
                return -EINVAL;
@@ -156,7 +155,7 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq,
        if (!bio_flagged(bio, BIO_USER_MAPPED))
                rq->cmd_flags |= REQ_COPY_USER;
 
-       rq->buffer = rq->data = NULL;
+       rq->buffer = NULL;
        return 0;
 unmap_rq:
        blk_rq_unmap_user(bio);
@@ -235,7 +234,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
        blk_queue_bounce(q, &bio);
        bio_get(bio);
        blk_rq_bio_prep(q, rq, bio);
-       rq->buffer = rq->data = NULL;
+       rq->buffer = NULL;
        return 0;
 }
 EXPORT_SYMBOL(blk_rq_map_user_iov);
@@ -282,7 +281,8 @@ EXPORT_SYMBOL(blk_rq_unmap_user);
  *
  * Description:
  *    Data will be mapped directly if possible. Otherwise a bounce
- *    buffer is used.
+ *    buffer is used. Can be called multple times to append multple
+ *    buffers.
  */
 int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
                    unsigned int len, gfp_t gfp_mask)
@@ -290,8 +290,9 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
        int reading = rq_data_dir(rq) == READ;
        int do_copy = 0;
        struct bio *bio;
+       int ret;
 
-       if (len > (q->max_hw_sectors << 9))
+       if (len > (queue_max_hw_sectors(q) << 9))
                return -EINVAL;
        if (!len || !kbuf)
                return -EINVAL;
@@ -311,9 +312,15 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
        if (do_copy)
                rq->cmd_flags |= REQ_COPY_USER;
 
-       blk_rq_bio_prep(q, rq, bio);
+       ret = blk_rq_append_bio(q, rq, bio);
+       if (unlikely(ret)) {
+               /* request is too big */
+               bio_put(bio);
+               return ret;
+       }
+
        blk_queue_bounce(q, &rq->bio);
-       rq->buffer = rq->data = NULL;
+       rq->buffer = NULL;
        return 0;
 }
 EXPORT_SYMBOL(blk_rq_map_kern);
index 23d2a6fe34a38b2e4f662bfeab9b2ddbbc60e8c6..39ce64432ba6d4cdcff6427851fe19aac172a2d7 100644 (file)
@@ -9,35 +9,6 @@
 
 #include "blk.h"
 
-void blk_recalc_rq_sectors(struct request *rq, int nsect)
-{
-       if (blk_fs_request(rq) || blk_discard_rq(rq)) {
-               rq->hard_sector += nsect;
-               rq->hard_nr_sectors -= nsect;
-
-               /*
-                * Move the I/O submission pointers ahead if required.
-                */
-               if ((rq->nr_sectors >= rq->hard_nr_sectors) &&
-                   (rq->sector <= rq->hard_sector)) {
-                       rq->sector = rq->hard_sector;
-                       rq->nr_sectors = rq->hard_nr_sectors;
-                       rq->hard_cur_sectors = bio_cur_sectors(rq->bio);
-                       rq->current_nr_sectors = rq->hard_cur_sectors;
-                       rq->buffer = bio_data(rq->bio);
-               }
-
-               /*
-                * if total number of sectors is less than the first segment
-                * size, something has gone terribly wrong
-                */
-               if (rq->nr_sectors < rq->current_nr_sectors) {
-                       printk(KERN_ERR "blk: request botched\n");
-                       rq->nr_sectors = rq->current_nr_sectors;
-               }
-       }
-}
-
 static unsigned int __blk_recalc_rq_segments(struct request_queue *q,
                                             struct bio *bio)
 {
@@ -61,11 +32,12 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q,
                         * never considered part of another segment, since that
                         * might change with the bounce page.
                         */
-                       high = page_to_pfn(bv->bv_page) > q->bounce_pfn;
+                       high = page_to_pfn(bv->bv_page) > queue_bounce_pfn(q);
                        if (high || highprv)
                                goto new_segment;
                        if (cluster) {
-                               if (seg_size + bv->bv_len > q->max_segment_size)
+                               if (seg_size + bv->bv_len
+                                   > queue_max_segment_size(q))
                                        goto new_segment;
                                if (!BIOVEC_PHYS_MERGEABLE(bvprv, bv))
                                        goto new_segment;
@@ -120,7 +92,7 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
                return 0;
 
        if (bio->bi_seg_back_size + nxt->bi_seg_front_size >
-           q->max_segment_size)
+           queue_max_segment_size(q))
                return 0;
 
        if (!bio_has_data(bio))
@@ -163,7 +135,7 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq,
                int nbytes = bvec->bv_len;
 
                if (bvprv && cluster) {
-                       if (sg->length + nbytes > q->max_segment_size)
+                       if (sg->length + nbytes > queue_max_segment_size(q))
                                goto new_segment;
 
                        if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec))
@@ -199,8 +171,9 @@ new_segment:
 
 
        if (unlikely(rq->cmd_flags & REQ_COPY_USER) &&
-           (rq->data_len & q->dma_pad_mask)) {
-               unsigned int pad_len = (q->dma_pad_mask & ~rq->data_len) + 1;
+           (blk_rq_bytes(rq) & q->dma_pad_mask)) {
+               unsigned int pad_len =
+                       (q->dma_pad_mask & ~blk_rq_bytes(rq)) + 1;
 
                sg->length += pad_len;
                rq->extra_len += pad_len;
@@ -233,8 +206,8 @@ static inline int ll_new_hw_segment(struct request_queue *q,
 {
        int nr_phys_segs = bio_phys_segments(q, bio);
 
-       if (req->nr_phys_segments + nr_phys_segs > q->max_hw_segments
-           || req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) {
+       if (req->nr_phys_segments + nr_phys_segs > queue_max_hw_segments(q) ||
+           req->nr_phys_segments + nr_phys_segs > queue_max_phys_segments(q)) {
                req->cmd_flags |= REQ_NOMERGE;
                if (req == q->last_merge)
                        q->last_merge = NULL;
@@ -255,11 +228,11 @@ int ll_back_merge_fn(struct request_queue *q, struct request *req,
        unsigned short max_sectors;
 
        if (unlikely(blk_pc_request(req)))
-               max_sectors = q->max_hw_sectors;
+               max_sectors = queue_max_hw_sectors(q);
        else
-               max_sectors = q->max_sectors;
+               max_sectors = queue_max_sectors(q);
 
-       if (req->nr_sectors + bio_sectors(bio) > max_sectors) {
+       if (blk_rq_sectors(req) + bio_sectors(bio) > max_sectors) {
                req->cmd_flags |= REQ_NOMERGE;
                if (req == q->last_merge)
                        q->last_merge = NULL;
@@ -279,12 +252,12 @@ int ll_front_merge_fn(struct request_queue *q, struct request *req,
        unsigned short max_sectors;
 
        if (unlikely(blk_pc_request(req)))
-               max_sectors = q->max_hw_sectors;
+               max_sectors = queue_max_hw_sectors(q);
        else
-               max_sectors = q->max_sectors;
+               max_sectors = queue_max_sectors(q);
 
 
-       if (req->nr_sectors + bio_sectors(bio) > max_sectors) {
+       if (blk_rq_sectors(req) + bio_sectors(bio) > max_sectors) {
                req->cmd_flags |= REQ_NOMERGE;
                if (req == q->last_merge)
                        q->last_merge = NULL;
@@ -315,7 +288,7 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
        /*
         * Will it become too large?
         */
-       if ((req->nr_sectors + next->nr_sectors) > q->max_sectors)
+       if ((blk_rq_sectors(req) + blk_rq_sectors(next)) > queue_max_sectors(q))
                return 0;
 
        total_phys_segments = req->nr_phys_segments + next->nr_phys_segments;
@@ -327,10 +300,10 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
                total_phys_segments--;
        }
 
-       if (total_phys_segments > q->max_phys_segments)
+       if (total_phys_segments > queue_max_phys_segments(q))
                return 0;
 
-       if (total_phys_segments > q->max_hw_segments)
+       if (total_phys_segments > queue_max_hw_segments(q))
                return 0;
 
        /* Merge is OK... */
@@ -345,7 +318,7 @@ static void blk_account_io_merge(struct request *req)
                int cpu;
 
                cpu = part_stat_lock();
-               part = disk_map_sector_rcu(req->rq_disk, req->sector);
+               part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
 
                part_round_stats(cpu, part);
                part_dec_in_flight(part);
@@ -366,7 +339,7 @@ static int attempt_merge(struct request_queue *q, struct request *req,
        /*
         * not contiguous
         */
-       if (req->sector + req->nr_sectors != next->sector)
+       if (blk_rq_pos(req) + blk_rq_sectors(req) != blk_rq_pos(next))
                return 0;
 
        if (rq_data_dir(req) != rq_data_dir(next)
@@ -398,7 +371,7 @@ static int attempt_merge(struct request_queue *q, struct request *req,
        req->biotail->bi_next = next->bio;
        req->biotail = next->biotail;
 
-       req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors;
+       req->__data_len += blk_rq_bytes(next);
 
        elv_merge_requests(q, req, next);
 
index 57af728d94bb08732e9d217a94dafe9bae9ef992..1c4df9bf681368af564dec31a47f493929ce6929 100644 (file)
@@ -134,7 +134,7 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
        q->backing_dev_info.state = 0;
        q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY;
        blk_queue_max_sectors(q, SAFE_MAX_SECTORS);
-       blk_queue_hardsect_size(q, 512);
+       blk_queue_logical_block_size(q, 512);
        blk_queue_dma_alignment(q, 511);
        blk_queue_congestion_threshold(q);
        q->nr_batching = BLK_BATCH_REQ;
@@ -179,16 +179,16 @@ void blk_queue_bounce_limit(struct request_queue *q, u64 dma_mask)
         */
        if (b_pfn < (min_t(u64, 0xffffffffUL, BLK_BOUNCE_HIGH) >> PAGE_SHIFT))
                dma = 1;
-       q->bounce_pfn = max_low_pfn;
+       q->limits.bounce_pfn = max_low_pfn;
 #else
        if (b_pfn < blk_max_low_pfn)
                dma = 1;
-       q->bounce_pfn = b_pfn;
+       q->limits.bounce_pfn = b_pfn;
 #endif
        if (dma) {
                init_emergency_isa_pool();
                q->bounce_gfp = GFP_NOIO | GFP_DMA;
-               q->bounce_pfn = b_pfn;
+               q->limits.bounce_pfn = b_pfn;
        }
 }
 EXPORT_SYMBOL(blk_queue_bounce_limit);
@@ -211,14 +211,23 @@ void blk_queue_max_sectors(struct request_queue *q, unsigned int max_sectors)
        }
 
        if (BLK_DEF_MAX_SECTORS > max_sectors)
-               q->max_hw_sectors = q->max_sectors = max_sectors;
+               q->limits.max_hw_sectors = q->limits.max_sectors = max_sectors;
        else {
-               q->max_sectors = BLK_DEF_MAX_SECTORS;
-               q->max_hw_sectors = max_sectors;
+               q->limits.max_sectors = BLK_DEF_MAX_SECTORS;
+               q->limits.max_hw_sectors = max_sectors;
        }
 }
 EXPORT_SYMBOL(blk_queue_max_sectors);
 
+void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_sectors)
+{
+       if (BLK_DEF_MAX_SECTORS > max_sectors)
+               q->limits.max_hw_sectors = BLK_DEF_MAX_SECTORS;
+       else
+               q->limits.max_hw_sectors = max_sectors;
+}
+EXPORT_SYMBOL(blk_queue_max_hw_sectors);
+
 /**
  * blk_queue_max_phys_segments - set max phys segments for a request for this queue
  * @q:  the request queue for the device
@@ -238,7 +247,7 @@ void blk_queue_max_phys_segments(struct request_queue *q,
                       __func__, max_segments);
        }
 
-       q->max_phys_segments = max_segments;
+       q->limits.max_phys_segments = max_segments;
 }
 EXPORT_SYMBOL(blk_queue_max_phys_segments);
 
@@ -262,7 +271,7 @@ void blk_queue_max_hw_segments(struct request_queue *q,
                       __func__, max_segments);
        }
 
-       q->max_hw_segments = max_segments;
+       q->limits.max_hw_segments = max_segments;
 }
 EXPORT_SYMBOL(blk_queue_max_hw_segments);
 
@@ -283,26 +292,110 @@ void blk_queue_max_segment_size(struct request_queue *q, unsigned int max_size)
                       __func__, max_size);
        }
 
-       q->max_segment_size = max_size;
+       q->limits.max_segment_size = max_size;
 }
 EXPORT_SYMBOL(blk_queue_max_segment_size);
 
 /**
- * blk_queue_hardsect_size - set hardware sector size for the queue
+ * blk_queue_logical_block_size - set logical block size for the queue
  * @q:  the request queue for the device
- * @size:  the hardware sector size, in bytes
+ * @size:  the logical block size, in bytes
  *
  * Description:
- *   This should typically be set to the lowest possible sector size
- *   that the hardware can operate on (possible without reverting to
- *   even internal read-modify-write operations). Usually the default
- *   of 512 covers most hardware.
+ *   This should be set to the lowest possible block size that the
+ *   storage device can address.  The default of 512 covers most
+ *   hardware.
  **/
-void blk_queue_hardsect_size(struct request_queue *q, unsigned short size)
+void blk_queue_logical_block_size(struct request_queue *q, unsigned short size)
+{
+       q->limits.logical_block_size = size;
+
+       if (q->limits.physical_block_size < size)
+               q->limits.physical_block_size = size;
+
+       if (q->limits.io_min < q->limits.physical_block_size)
+               q->limits.io_min = q->limits.physical_block_size;
+}
+EXPORT_SYMBOL(blk_queue_logical_block_size);
+
+/**
+ * blk_queue_physical_block_size - set physical block size for the queue
+ * @q:  the request queue for the device
+ * @size:  the physical block size, in bytes
+ *
+ * Description:
+ *   This should be set to the lowest possible sector size that the
+ *   hardware can operate on without reverting to read-modify-write
+ *   operations.
+ */
+void blk_queue_physical_block_size(struct request_queue *q, unsigned short size)
+{
+       q->limits.physical_block_size = size;
+
+       if (q->limits.physical_block_size < q->limits.logical_block_size)
+               q->limits.physical_block_size = q->limits.logical_block_size;
+
+       if (q->limits.io_min < q->limits.physical_block_size)
+               q->limits.io_min = q->limits.physical_block_size;
+}
+EXPORT_SYMBOL(blk_queue_physical_block_size);
+
+/**
+ * blk_queue_alignment_offset - set physical block alignment offset
+ * @q: the request queue for the device
+ * @alignment: alignment offset in bytes
+ *
+ * Description:
+ *   Some devices are naturally misaligned to compensate for things like
+ *   the legacy DOS partition table 63-sector offset.  Low-level drivers
+ *   should call this function for devices whose first sector is not
+ *   naturally aligned.
+ */
+void blk_queue_alignment_offset(struct request_queue *q, unsigned int offset)
 {
-       q->hardsect_size = size;
+       q->limits.alignment_offset =
+               offset & (q->limits.physical_block_size - 1);
+       q->limits.misaligned = 0;
 }
-EXPORT_SYMBOL(blk_queue_hardsect_size);
+EXPORT_SYMBOL(blk_queue_alignment_offset);
+
+/**
+ * blk_queue_io_min - set minimum request size for the queue
+ * @q: the request queue for the device
+ * @io_min:  smallest I/O size in bytes
+ *
+ * Description:
+ *   Some devices have an internal block size bigger than the reported
+ *   hardware sector size.  This function can be used to signal the
+ *   smallest I/O the device can perform without incurring a performance
+ *   penalty.
+ */
+void blk_queue_io_min(struct request_queue *q, unsigned int min)
+{
+       q->limits.io_min = min;
+
+       if (q->limits.io_min < q->limits.logical_block_size)
+               q->limits.io_min = q->limits.logical_block_size;
+
+       if (q->limits.io_min < q->limits.physical_block_size)
+               q->limits.io_min = q->limits.physical_block_size;
+}
+EXPORT_SYMBOL(blk_queue_io_min);
+
+/**
+ * blk_queue_io_opt - set optimal request size for the queue
+ * @q: the request queue for the device
+ * @io_opt:  optimal request size in bytes
+ *
+ * Description:
+ *   Drivers can call this function to set the preferred I/O request
+ *   size for devices that report such a value.
+ */
+void blk_queue_io_opt(struct request_queue *q, unsigned int opt)
+{
+       q->limits.io_opt = opt;
+}
+EXPORT_SYMBOL(blk_queue_io_opt);
 
 /*
  * Returns the minimum that is _not_ zero, unless both are zero.
@@ -317,14 +410,27 @@ EXPORT_SYMBOL(blk_queue_hardsect_size);
 void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b)
 {
        /* zero is "infinity" */
-       t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
-       t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
-       t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask, b->seg_boundary_mask);
+       t->limits.max_sectors = min_not_zero(queue_max_sectors(t),
+                                            queue_max_sectors(b));
+
+       t->limits.max_hw_sectors = min_not_zero(queue_max_hw_sectors(t),
+                                               queue_max_hw_sectors(b));
+
+       t->limits.seg_boundary_mask = min_not_zero(queue_segment_boundary(t),
+                                                  queue_segment_boundary(b));
+
+       t->limits.max_phys_segments = min_not_zero(queue_max_phys_segments(t),
+                                                  queue_max_phys_segments(b));
+
+       t->limits.max_hw_segments = min_not_zero(queue_max_hw_segments(t),
+                                                queue_max_hw_segments(b));
+
+       t->limits.max_segment_size = min_not_zero(queue_max_segment_size(t),
+                                                 queue_max_segment_size(b));
+
+       t->limits.logical_block_size = max(queue_logical_block_size(t),
+                                          queue_logical_block_size(b));
 
-       t->max_phys_segments = min_not_zero(t->max_phys_segments, b->max_phys_segments);
-       t->max_hw_segments = min_not_zero(t->max_hw_segments, b->max_hw_segments);
-       t->max_segment_size = min_not_zero(t->max_segment_size, b->max_segment_size);
-       t->hardsect_size = max(t->hardsect_size, b->hardsect_size);
        if (!t->queue_lock)
                WARN_ON_ONCE(1);
        else if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) {
@@ -336,6 +442,109 @@ void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b)
 }
 EXPORT_SYMBOL(blk_queue_stack_limits);
 
+/**
+ * blk_stack_limits - adjust queue_limits for stacked devices
+ * @t: the stacking driver limits (top)
+ * @b:  the underlying queue limits (bottom)
+ * @offset:  offset to beginning of data within component device
+ *
+ * Description:
+ *    Merges two queue_limit structs.  Returns 0 if alignment didn't
+ *    change.  Returns -1 if adding the bottom device caused
+ *    misalignment.
+ */
+int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
+                    sector_t offset)
+{
+       t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
+       t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
+       t->bounce_pfn = min_not_zero(t->bounce_pfn, b->bounce_pfn);
+
+       t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask,
+                                           b->seg_boundary_mask);
+
+       t->max_phys_segments = min_not_zero(t->max_phys_segments,
+                                           b->max_phys_segments);
+
+       t->max_hw_segments = min_not_zero(t->max_hw_segments,
+                                         b->max_hw_segments);
+
+       t->max_segment_size = min_not_zero(t->max_segment_size,
+                                          b->max_segment_size);
+
+       t->logical_block_size = max(t->logical_block_size,
+                                   b->logical_block_size);
+
+       t->physical_block_size = max(t->physical_block_size,
+                                    b->physical_block_size);
+
+       t->io_min = max(t->io_min, b->io_min);
+       t->no_cluster |= b->no_cluster;
+
+       /* Bottom device offset aligned? */
+       if (offset &&
+           (offset & (b->physical_block_size - 1)) != b->alignment_offset) {
+               t->misaligned = 1;
+               return -1;
+       }
+
+       /* If top has no alignment offset, inherit from bottom */
+       if (!t->alignment_offset)
+               t->alignment_offset =
+                       b->alignment_offset & (b->physical_block_size - 1);
+
+       /* Top device aligned on logical block boundary? */
+       if (t->alignment_offset & (t->logical_block_size - 1)) {
+               t->misaligned = 1;
+               return -1;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(blk_stack_limits);
+
+/**
+ * disk_stack_limits - adjust queue limits for stacked drivers
+ * @disk:  MD/DM gendisk (top)
+ * @bdev:  the underlying block device (bottom)
+ * @offset:  offset to beginning of data within component device
+ *
+ * Description:
+ *    Merges the limits for two queues.  Returns 0 if alignment
+ *    didn't change.  Returns -1 if adding the bottom device caused
+ *    misalignment.
+ */
+void disk_stack_limits(struct gendisk *disk, struct block_device *bdev,
+                      sector_t offset)
+{
+       struct request_queue *t = disk->queue;
+       struct request_queue *b = bdev_get_queue(bdev);
+
+       offset += get_start_sect(bdev) << 9;
+
+       if (blk_stack_limits(&t->limits, &b->limits, offset) < 0) {
+               char top[BDEVNAME_SIZE], bottom[BDEVNAME_SIZE];
+
+               disk_name(disk, 0, top);
+               bdevname(bdev, bottom);
+
+               printk(KERN_NOTICE "%s: Warning: Device %s is misaligned\n",
+                      top, bottom);
+       }
+
+       if (!t->queue_lock)
+               WARN_ON_ONCE(1);
+       else if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(t->queue_lock, flags);
+               if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags))
+                       queue_flag_clear(QUEUE_FLAG_CLUSTER, t);
+               spin_unlock_irqrestore(t->queue_lock, flags);
+       }
+}
+EXPORT_SYMBOL(disk_stack_limits);
+
 /**
  * blk_queue_dma_pad - set pad mask
  * @q:     the request queue for the device
@@ -396,11 +605,11 @@ int blk_queue_dma_drain(struct request_queue *q,
                               dma_drain_needed_fn *dma_drain_needed,
                               void *buf, unsigned int size)
 {
-       if (q->max_hw_segments < 2 || q->max_phys_segments < 2)
+       if (queue_max_hw_segments(q) < 2 || queue_max_phys_segments(q) < 2)
                return -EINVAL;
        /* make room for appending the drain */
-       --q->max_hw_segments;
-       --q->max_phys_segments;
+       blk_queue_max_hw_segments(q, queue_max_hw_segments(q) - 1);
+       blk_queue_max_phys_segments(q, queue_max_phys_segments(q) - 1);
        q->dma_drain_needed = dma_drain_needed;
        q->dma_drain_buffer = buf;
        q->dma_drain_size = size;
@@ -422,7 +631,7 @@ void blk_queue_segment_boundary(struct request_queue *q, unsigned long mask)
                       __func__, mask);
        }
 
-       q->seg_boundary_mask = mask;
+       q->limits.seg_boundary_mask = mask;
 }
 EXPORT_SYMBOL(blk_queue_segment_boundary);
 
index 3ff9bba3379a84891ddbc97450fcdbddf6e42a1a..b1cd04087d6a4db5f8ba3e2d9b4f8db1221ed424 100644 (file)
@@ -95,21 +95,36 @@ queue_ra_store(struct request_queue *q, const char *page, size_t count)
 
 static ssize_t queue_max_sectors_show(struct request_queue *q, char *page)
 {
-       int max_sectors_kb = q->max_sectors >> 1;
+       int max_sectors_kb = queue_max_sectors(q) >> 1;
 
        return queue_var_show(max_sectors_kb, (page));
 }
 
-static ssize_t queue_hw_sector_size_show(struct request_queue *q, char *page)
+static ssize_t queue_logical_block_size_show(struct request_queue *q, char *page)
 {
-       return queue_var_show(q->hardsect_size, page);
+       return queue_var_show(queue_logical_block_size(q), page);
+}
+
+static ssize_t queue_physical_block_size_show(struct request_queue *q, char *page)
+{
+       return queue_var_show(queue_physical_block_size(q), page);
+}
+
+static ssize_t queue_io_min_show(struct request_queue *q, char *page)
+{
+       return queue_var_show(queue_io_min(q), page);
+}
+
+static ssize_t queue_io_opt_show(struct request_queue *q, char *page)
+{
+       return queue_var_show(queue_io_opt(q), page);
 }
 
 static ssize_t
 queue_max_sectors_store(struct request_queue *q, const char *page, size_t count)
 {
        unsigned long max_sectors_kb,
-                       max_hw_sectors_kb = q->max_hw_sectors >> 1,
+               max_hw_sectors_kb = queue_max_hw_sectors(q) >> 1,
                        page_kb = 1 << (PAGE_CACHE_SHIFT - 10);
        ssize_t ret = queue_var_store(&max_sectors_kb, page, count);
 
@@ -117,7 +132,7 @@ queue_max_sectors_store(struct request_queue *q, const char *page, size_t count)
                return -EINVAL;
 
        spin_lock_irq(q->queue_lock);
-       q->max_sectors = max_sectors_kb << 1;
+       blk_queue_max_sectors(q, max_sectors_kb << 1);
        spin_unlock_irq(q->queue_lock);
 
        return ret;
@@ -125,7 +140,7 @@ queue_max_sectors_store(struct request_queue *q, const char *page, size_t count)
 
 static ssize_t queue_max_hw_sectors_show(struct request_queue *q, char *page)
 {
-       int max_hw_sectors_kb = q->max_hw_sectors >> 1;
+       int max_hw_sectors_kb = queue_max_hw_sectors(q) >> 1;
 
        return queue_var_show(max_hw_sectors_kb, (page));
 }
@@ -249,7 +264,27 @@ static struct queue_sysfs_entry queue_iosched_entry = {
 
 static struct queue_sysfs_entry queue_hw_sector_size_entry = {
        .attr = {.name = "hw_sector_size", .mode = S_IRUGO },
-       .show = queue_hw_sector_size_show,
+       .show = queue_logical_block_size_show,
+};
+
+static struct queue_sysfs_entry queue_logical_block_size_entry = {
+       .attr = {.name = "logical_block_size", .mode = S_IRUGO },
+       .show = queue_logical_block_size_show,
+};
+
+static struct queue_sysfs_entry queue_physical_block_size_entry = {
+       .attr = {.name = "physical_block_size", .mode = S_IRUGO },
+       .show = queue_physical_block_size_show,
+};
+
+static struct queue_sysfs_entry queue_io_min_entry = {
+       .attr = {.name = "minimum_io_size", .mode = S_IRUGO },
+       .show = queue_io_min_show,
+};
+
+static struct queue_sysfs_entry queue_io_opt_entry = {
+       .attr = {.name = "optimal_io_size", .mode = S_IRUGO },
+       .show = queue_io_opt_show,
 };
 
 static struct queue_sysfs_entry queue_nonrot_entry = {
@@ -283,6 +318,10 @@ static struct attribute *default_attrs[] = {
        &queue_max_sectors_entry.attr,
        &queue_iosched_entry.attr,
        &queue_hw_sector_size_entry.attr,
+       &queue_logical_block_size_entry.attr,
+       &queue_physical_block_size_entry.attr,
+       &queue_io_min_entry.attr,
+       &queue_io_opt_entry.attr,
        &queue_nonrot_entry.attr,
        &queue_nomerges_entry.attr,
        &queue_rq_affinity_entry.attr,
@@ -383,22 +422,26 @@ struct kobj_type blk_queue_ktype = {
 int blk_register_queue(struct gendisk *disk)
 {
        int ret;
+       struct device *dev = disk_to_dev(disk);
 
        struct request_queue *q = disk->queue;
 
        if (WARN_ON(!q))
                return -ENXIO;
 
-       if (!q->request_fn)
-               return 0;
+       ret = blk_trace_init_sysfs(dev);
+       if (ret)
+               return ret;
 
-       ret = kobject_add(&q->kobj, kobject_get(&disk_to_dev(disk)->kobj),
-                         "%s", "queue");
+       ret = kobject_add(&q->kobj, kobject_get(&dev->kobj), "%s", "queue");
        if (ret < 0)
                return ret;
 
        kobject_uevent(&q->kobj, KOBJ_ADD);
 
+       if (!q->request_fn)
+               return 0;
+
        ret = elv_register_queue(q);
        if (ret) {
                kobject_uevent(&q->kobj, KOBJ_REMOVE);
index 3c518e3303ae34113516924f9d73a58b94a1e75c..2e5cfeb59333ecc088576324f1d6e0e88faf3bed 100644 (file)
@@ -336,7 +336,7 @@ EXPORT_SYMBOL(blk_queue_end_tag);
 int blk_queue_start_tag(struct request_queue *q, struct request *rq)
 {
        struct blk_queue_tag *bqt = q->queue_tags;
-       unsigned max_depth, offset;
+       unsigned max_depth;
        int tag;
 
        if (unlikely((rq->cmd_flags & REQ_QUEUED))) {
@@ -355,13 +355,16 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq)
         * to starve sync IO on behalf of flooding async IO.
         */
        max_depth = bqt->max_depth;
-       if (rq_is_sync(rq))
-               offset = 0;
-       else
-               offset = max_depth >> 2;
+       if (!rq_is_sync(rq) && max_depth > 1) {
+               max_depth -= 2;
+               if (!max_depth)
+                       max_depth = 1;
+               if (q->in_flight[0] > max_depth)
+                       return 1;
+       }
 
        do {
-               tag = find_next_zero_bit(bqt->tag_map, max_depth, offset);
+               tag = find_first_zero_bit(bqt->tag_map, max_depth);
                if (tag >= max_depth)
                        return 1;
 
@@ -374,7 +377,7 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq)
        rq->cmd_flags |= REQ_QUEUED;
        rq->tag = tag;
        bqt->tag_index[tag] = rq;
-       blkdev_dequeue_request(rq);
+       blk_start_request(rq);
        list_add(&rq->queuelist, &q->tag_busy_list);
        return 0;
 }
index 1ec0d503cacdc95bf296776ca2dc2d1e9ac4b108..1ba7e0aca8781b55ce14fa54491da8f81505b747 100644 (file)
@@ -122,10 +122,8 @@ void blk_rq_timed_out_timer(unsigned long data)
                        if (blk_mark_rq_complete(rq))
                                continue;
                        blk_rq_timed_out(rq);
-               } else {
-                       if (!next || time_after(next, rq->deadline))
-                               next = rq->deadline;
-               }
+               } else if (!next || time_after(next, rq->deadline))
+                       next = rq->deadline;
        }
 
        /*
@@ -176,16 +174,14 @@ void blk_add_timer(struct request *req)
        BUG_ON(!list_empty(&req->timeout_list));
        BUG_ON(test_bit(REQ_ATOM_COMPLETE, &req->atomic_flags));
 
-       if (req->timeout)
-               req->deadline = jiffies + req->timeout;
-       else {
-               req->deadline = jiffies + q->rq_timeout;
-               /*
-                * Some LLDs, like scsi, peek at the timeout to prevent
-                * a command from being retried forever.
-                */
+       /*
+        * Some LLDs, like scsi, peek at the timeout to prevent a
+        * command from being retried forever.
+        */
+       if (!req->timeout)
                req->timeout = q->rq_timeout;
-       }
+
+       req->deadline = jiffies + req->timeout;
        list_add_tail(&req->timeout_list, &q->timeout_list);
 
        /*
index 79c85f7c9ff50fb33fb89619a744c0f1d3e1686b..3fae6add54301495ffbdd1c3e6e37b559b3c4482 100644 (file)
@@ -13,6 +13,9 @@ extern struct kobj_type blk_queue_ktype;
 void init_request_from_bio(struct request *req, struct bio *bio);
 void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
                        struct bio *bio);
+int blk_rq_append_bio(struct request_queue *q, struct request *rq,
+                     struct bio *bio);
+void blk_dequeue_request(struct request *rq);
 void __blk_queue_free_tags(struct request_queue *q);
 
 void blk_unplug_work(struct work_struct *work);
@@ -43,6 +46,43 @@ static inline void blk_clear_rq_complete(struct request *rq)
        clear_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags);
 }
 
+/*
+ * Internal elevator interface
+ */
+#define ELV_ON_HASH(rq)                (!hlist_unhashed(&(rq)->hash))
+
+static inline struct request *__elv_next_request(struct request_queue *q)
+{
+       struct request *rq;
+
+       while (1) {
+               while (!list_empty(&q->queue_head)) {
+                       rq = list_entry_rq(q->queue_head.next);
+                       if (blk_do_ordered(q, &rq))
+                               return rq;
+               }
+
+               if (!q->elevator->ops->elevator_dispatch_fn(q, 0))
+                       return NULL;
+       }
+}
+
+static inline void elv_activate_rq(struct request_queue *q, struct request *rq)
+{
+       struct elevator_queue *e = q->elevator;
+
+       if (e->ops->elevator_activate_req_fn)
+               e->ops->elevator_activate_req_fn(q, rq);
+}
+
+static inline void elv_deactivate_rq(struct request_queue *q, struct request *rq)
+{
+       struct elevator_queue *e = q->elevator;
+
+       if (e->ops->elevator_deactivate_req_fn)
+               e->ops->elevator_deactivate_req_fn(q, rq);
+}
+
 #ifdef CONFIG_FAIL_IO_TIMEOUT
 int blk_should_fake_timeout(struct request_queue *);
 ssize_t part_timeout_show(struct device *, struct device_attribute *, char *);
@@ -64,7 +104,6 @@ int ll_front_merge_fn(struct request_queue *q, struct request *req,
 int attempt_back_merge(struct request_queue *q, struct request *rq);
 int attempt_front_merge(struct request_queue *q, struct request *rq);
 void blk_recalc_rq_segments(struct request *rq);
-void blk_recalc_rq_sectors(struct request *rq, int nsect);
 
 void blk_queue_congestion_threshold(struct request_queue *q);
 
@@ -112,9 +151,17 @@ static inline int blk_cpu_to_group(int cpu)
 #endif
 }
 
+/*
+ * Contribute to IO statistics IFF:
+ *
+ *     a) it's attached to a gendisk, and
+ *     b) the queue had IO stats enabled when this request was started, and
+ *     c) it's a file system request or a discard request
+ */
 static inline int blk_do_io_stat(struct request *rq)
 {
-       return rq->rq_disk && blk_rq_io_stat(rq);
+       return rq->rq_disk && blk_rq_io_stat(rq) &&
+              (blk_fs_request(rq) || blk_discard_rq(rq));
 }
 
 #endif
index dd81be455e00b3c258357cd2537d200d06455e27..5358f9ae13c1797b7eda131c7033c73a0c525162 100644 (file)
@@ -446,15 +446,15 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
        }
 
        if (rq->next_rq) {
-               hdr->dout_resid = rq->data_len;
-               hdr->din_resid = rq->next_rq->data_len;
+               hdr->dout_resid = rq->resid_len;
+               hdr->din_resid = rq->next_rq->resid_len;
                blk_rq_unmap_user(bidi_bio);
                rq->next_rq->bio = NULL;
                blk_put_request(rq->next_rq);
        } else if (rq_data_dir(rq) == READ)
-               hdr->din_resid = rq->data_len;
+               hdr->din_resid = rq->resid_len;
        else
-               hdr->dout_resid = rq->data_len;
+               hdr->dout_resid = rq->resid_len;
 
        /*
         * If the request generated a negative error number, return it
index a55a9bd75bd1baf616a3a1b7118acaeee328759f..ef2f72d4243407ccfec220c867028f28b013b751 100644 (file)
@@ -349,8 +349,8 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
        else if (rq_is_meta(rq2) && !rq_is_meta(rq1))
                return rq2;
 
-       s1 = rq1->sector;
-       s2 = rq2->sector;
+       s1 = blk_rq_pos(rq1);
+       s2 = blk_rq_pos(rq2);
 
        last = cfqd->last_position;
 
@@ -579,9 +579,9 @@ cfq_prio_tree_lookup(struct cfq_data *cfqd, struct rb_root *root,
                 * Sort strictly based on sector.  Smallest to the left,
                 * largest to the right.
                 */
-               if (sector > cfqq->next_rq->sector)
+               if (sector > blk_rq_pos(cfqq->next_rq))
                        n = &(*p)->rb_right;
-               else if (sector < cfqq->next_rq->sector)
+               else if (sector < blk_rq_pos(cfqq->next_rq))
                        n = &(*p)->rb_left;
                else
                        break;
@@ -611,8 +611,8 @@ static void cfq_prio_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq)
                return;
 
        cfqq->p_root = &cfqd->prio_trees[cfqq->org_ioprio];
-       __cfqq = cfq_prio_tree_lookup(cfqd, cfqq->p_root, cfqq->next_rq->sector,
-                                        &parent, &p);
+       __cfqq = cfq_prio_tree_lookup(cfqd, cfqq->p_root,
+                                     blk_rq_pos(cfqq->next_rq), &parent, &p);
        if (!__cfqq) {
                rb_link_node(&cfqq->p_node, parent, p);
                rb_insert_color(&cfqq->p_node, cfqq->p_root);
@@ -760,7 +760,7 @@ static void cfq_activate_request(struct request_queue *q, struct request *rq)
        cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "activate rq, drv=%d",
                                                cfqd->rq_in_driver);
 
-       cfqd->last_position = rq->hard_sector + rq->hard_nr_sectors;
+       cfqd->last_position = blk_rq_pos(rq) + blk_rq_sectors(rq);
 }
 
 static void cfq_deactivate_request(struct request_queue *q, struct request *rq)
@@ -949,10 +949,10 @@ static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd,
 static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd,
                                          struct request *rq)
 {
-       if (rq->sector >= cfqd->last_position)
-               return rq->sector - cfqd->last_position;
+       if (blk_rq_pos(rq) >= cfqd->last_position)
+               return blk_rq_pos(rq) - cfqd->last_position;
        else
-               return cfqd->last_position - rq->sector;
+               return cfqd->last_position - blk_rq_pos(rq);
 }
 
 #define CIC_SEEK_THR   8 * 1024
@@ -996,7 +996,7 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
        if (cfq_rq_close(cfqd, __cfqq->next_rq))
                return __cfqq;
 
-       if (__cfqq->next_rq->sector < sector)
+       if (blk_rq_pos(__cfqq->next_rq) < sector)
                node = rb_next(&__cfqq->p_node);
        else
                node = rb_prev(&__cfqq->p_node);
@@ -1282,7 +1282,7 @@ static void cfq_dispatch_request(struct cfq_data *cfqd, struct cfq_queue *cfqq)
        if (!cfqd->active_cic) {
                struct cfq_io_context *cic = RQ_CIC(rq);
 
-               atomic_inc(&cic->ioc->refcount);
+               atomic_long_inc(&cic->ioc->refcount);
                cfqd->active_cic = cic;
        }
 }
@@ -1918,10 +1918,10 @@ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
 
        if (!cic->last_request_pos)
                sdist = 0;
-       else if (cic->last_request_pos < rq->sector)
-               sdist = rq->sector - cic->last_request_pos;
+       else if (cic->last_request_pos < blk_rq_pos(rq))
+               sdist = blk_rq_pos(rq) - cic->last_request_pos;
        else
-               sdist = cic->last_request_pos - rq->sector;
+               sdist = cic->last_request_pos - blk_rq_pos(rq);
 
        /*
         * Don't allow the seek distance to get too large from the
@@ -2071,7 +2071,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        cfq_update_io_seektime(cfqd, cic, rq);
        cfq_update_idle_window(cfqd, cfqq, cic);
 
-       cic->last_request_pos = rq->sector + rq->nr_sectors;
+       cic->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq);
 
        if (cfqq == cfqd->active_queue) {
                /*
@@ -2088,7 +2088,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                        if (blk_rq_bytes(rq) > PAGE_CACHE_SIZE ||
                            cfqd->busy_queues > 1) {
                                del_timer(&cfqd->idle_slice_timer);
-                               blk_start_queueing(cfqd->queue);
+                       __blk_run_queue(cfqd->queue);
                        }
                        cfq_mark_cfqq_must_dispatch(cfqq);
                }
@@ -2100,7 +2100,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                 * this new queue is RT and the current one is BE
                 */
                cfq_preempt_queue(cfqd, cfqq);
-               blk_start_queueing(cfqd->queue);
+               __blk_run_queue(cfqd->queue);
        }
 }
 
@@ -2345,7 +2345,7 @@ static void cfq_kick_queue(struct work_struct *work)
        struct request_queue *q = cfqd->queue;
 
        spin_lock_irq(q->queue_lock);
-       blk_start_queueing(q);
+       __blk_run_queue(cfqd->queue);
        spin_unlock_irq(q->queue_lock);
 }
 
index f87615dea46bbd9dfcdf0789f170c2b9b8512f6a..7865a34e0faaaba07cb9e4946dca6406b303bef1 100644 (file)
@@ -568,7 +568,7 @@ static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg)
        memcpy(&buts.name, &cbuts.name, 32);
 
        mutex_lock(&bdev->bd_mutex);
-       ret = do_blk_trace_setup(q, b, bdev->bd_dev, &buts);
+       ret = do_blk_trace_setup(q, b, bdev->bd_dev, bdev, &buts);
        mutex_unlock(&bdev->bd_mutex);
        if (ret)
                return ret;
@@ -763,10 +763,10 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
                return compat_put_int(arg, block_size(bdev));
        case BLKSSZGET: /* get block device hardware sector size */
-               return compat_put_int(arg, bdev_hardsect_size(bdev));
+               return compat_put_int(arg, bdev_logical_block_size(bdev));
        case BLKSECTGET:
                return compat_put_ushort(arg,
-                                        bdev_get_queue(bdev)->max_sectors);
+                                        queue_max_sectors(bdev_get_queue(bdev)));
        case BLKRASET: /* compatible, but no compat_ptr (!) */
        case BLKFRASET:
                if (!capable(CAP_SYS_ADMIN))
index c4d991d4adef0e7fd6e0d432941b88771d7c6530..b547cbca7b23a55dd9d1f0b444bed07d297fc646 100644 (file)
@@ -138,7 +138,7 @@ deadline_merge(struct request_queue *q, struct request **req, struct bio *bio)
 
                __rq = elv_rb_find(&dd->sort_list[bio_data_dir(bio)], sector);
                if (__rq) {
-                       BUG_ON(sector != __rq->sector);
+                       BUG_ON(sector != blk_rq_pos(__rq));
 
                        if (elv_rq_merge_ok(__rq, bio)) {
                                ret = ELEVATOR_FRONT_MERGE;
index 7073a9072577cdf3a0ae6e63c5ca247c2f493a5d..ca861927ba41b2dfc9ff80c139f6c8cc162fc251 100644 (file)
 #include <linux/compiler.h>
 #include <linux/delay.h>
 #include <linux/blktrace_api.h>
-#include <trace/block.h>
 #include <linux/hash.h>
 #include <linux/uaccess.h>
 
+#include <trace/events/block.h>
+
 #include "blk.h"
 
 static DEFINE_SPINLOCK(elv_list_lock);
 static LIST_HEAD(elv_list);
 
-DEFINE_TRACE(block_rq_abort);
-
 /*
  * Merge hash stuff.
  */
@@ -52,11 +51,7 @@ static const int elv_hash_shift = 6;
 #define ELV_HASH_FN(sec)       \
                (hash_long(ELV_HASH_BLOCK((sec)), elv_hash_shift))
 #define ELV_HASH_ENTRIES       (1 << elv_hash_shift)
-#define rq_hash_key(rq)                ((rq)->sector + (rq)->nr_sectors)
-#define ELV_ON_HASH(rq)                (!hlist_unhashed(&(rq)->hash))
-
-DEFINE_TRACE(block_rq_insert);
-DEFINE_TRACE(block_rq_issue);
+#define rq_hash_key(rq)                (blk_rq_pos(rq) + blk_rq_sectors(rq))
 
 /*
  * Query io scheduler to see if the current process issuing bio may be
@@ -120,9 +115,9 @@ static inline int elv_try_merge(struct request *__rq, struct bio *bio)
         * we can merge and sequence is ok, check if it's possible
         */
        if (elv_rq_merge_ok(__rq, bio)) {
-               if (__rq->sector + __rq->nr_sectors == bio->bi_sector)
+               if (blk_rq_pos(__rq) + blk_rq_sectors(__rq) == bio->bi_sector)
                        ret = ELEVATOR_BACK_MERGE;
-               else if (__rq->sector - bio_sectors(bio) == bio->bi_sector)
+               else if (blk_rq_pos(__rq) - bio_sectors(bio) == bio->bi_sector)
                        ret = ELEVATOR_FRONT_MERGE;
        }
 
@@ -310,22 +305,6 @@ void elevator_exit(struct elevator_queue *e)
 }
 EXPORT_SYMBOL(elevator_exit);
 
-static void elv_activate_rq(struct request_queue *q, struct request *rq)
-{
-       struct elevator_queue *e = q->elevator;
-
-       if (e->ops->elevator_activate_req_fn)
-               e->ops->elevator_activate_req_fn(q, rq);
-}
-
-static void elv_deactivate_rq(struct request_queue *q, struct request *rq)
-{
-       struct elevator_queue *e = q->elevator;
-
-       if (e->ops->elevator_deactivate_req_fn)
-               e->ops->elevator_deactivate_req_fn(q, rq);
-}
-
 static inline void __elv_rqhash_del(struct request *rq)
 {
        hlist_del_init(&rq->hash);
@@ -387,9 +366,9 @@ struct request *elv_rb_add(struct rb_root *root, struct request *rq)
                parent = *p;
                __rq = rb_entry(parent, struct request, rb_node);
 
-               if (rq->sector < __rq->sector)
+               if (blk_rq_pos(rq) < blk_rq_pos(__rq))
                        p = &(*p)->rb_left;
-               else if (rq->sector > __rq->sector)
+               else if (blk_rq_pos(rq) > blk_rq_pos(__rq))
                        p = &(*p)->rb_right;
                else
                        return __rq;
@@ -417,9 +396,9 @@ struct request *elv_rb_find(struct rb_root *root, sector_t sector)
        while (n) {
                rq = rb_entry(n, struct request, rb_node);
 
-               if (sector < rq->sector)
+               if (sector < blk_rq_pos(rq))
                        n = n->rb_left;
-               else if (sector > rq->sector)
+               else if (sector > blk_rq_pos(rq))
                        n = n->rb_right;
                else
                        return rq;
@@ -458,14 +437,14 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
                        break;
                if (pos->cmd_flags & stop_flags)
                        break;
-               if (rq->sector >= boundary) {
-                       if (pos->sector < boundary)
+               if (blk_rq_pos(rq) >= boundary) {
+                       if (blk_rq_pos(pos) < boundary)
                                continue;
                } else {
-                       if (pos->sector >= boundary)
+                       if (blk_rq_pos(pos) >= boundary)
                                break;
                }
-               if (rq->sector >= pos->sector)
+               if (blk_rq_pos(rq) >= blk_rq_pos(pos))
                        break;
        }
 
@@ -563,7 +542,7 @@ void elv_requeue_request(struct request_queue *q, struct request *rq)
         * in_flight count again
         */
        if (blk_account_rq(rq)) {
-               q->in_flight--;
+               q->in_flight[rq_is_sync(rq)]--;
                if (blk_sorted_rq(rq))
                        elv_deactivate_rq(q, rq);
        }
@@ -592,6 +571,9 @@ void elv_drain_elevator(struct request_queue *q)
  */
 void elv_quiesce_start(struct request_queue *q)
 {
+       if (!q->elevator)
+               return;
+
        queue_flag_set(QUEUE_FLAG_ELVSWITCH, q);
 
        /*
@@ -599,7 +581,7 @@ void elv_quiesce_start(struct request_queue *q)
         */
        elv_drain_elevator(q);
        while (q->rq.elvpriv) {
-               blk_start_queueing(q);
+               __blk_run_queue(q);
                spin_unlock_irq(q->queue_lock);
                msleep(10);
                spin_lock_irq(q->queue_lock);
@@ -643,8 +625,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where)
                 *   with anything.  There's no point in delaying queue
                 *   processing.
                 */
-               blk_remove_plug(q);
-               blk_start_queueing(q);
+               __blk_run_queue(q);
                break;
 
        case ELEVATOR_INSERT_SORT:
@@ -703,7 +684,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where)
 
        if (unplug_it && blk_queue_plugged(q)) {
                int nrq = q->rq.count[BLK_RW_SYNC] + q->rq.count[BLK_RW_ASYNC]
-                       - q->in_flight;
+                               - queue_in_flight(q);
 
                if (nrq >= q->unplug_thresh)
                        __generic_unplug_device(q);
@@ -759,117 +740,6 @@ void elv_add_request(struct request_queue *q, struct request *rq, int where,
 }
 EXPORT_SYMBOL(elv_add_request);
 
-static inline struct request *__elv_next_request(struct request_queue *q)
-{
-       struct request *rq;
-
-       while (1) {
-               while (!list_empty(&q->queue_head)) {
-                       rq = list_entry_rq(q->queue_head.next);
-                       if (blk_do_ordered(q, &rq))
-                               return rq;
-               }
-
-               if (!q->elevator->ops->elevator_dispatch_fn(q, 0))
-                       return NULL;
-       }
-}
-
-struct request *elv_next_request(struct request_queue *q)
-{
-       struct request *rq;
-       int ret;
-
-       while ((rq = __elv_next_request(q)) != NULL) {
-               if (!(rq->cmd_flags & REQ_STARTED)) {
-                       /*
-                        * This is the first time the device driver
-                        * sees this request (possibly after
-                        * requeueing).  Notify IO scheduler.
-                        */
-                       if (blk_sorted_rq(rq))
-                               elv_activate_rq(q, rq);
-
-                       /*
-                        * just mark as started even if we don't start
-                        * it, a request that has been delayed should
-                        * not be passed by new incoming requests
-                        */
-                       rq->cmd_flags |= REQ_STARTED;
-                       trace_block_rq_issue(q, rq);
-               }
-
-               if (!q->boundary_rq || q->boundary_rq == rq) {
-                       q->end_sector = rq_end_sector(rq);
-                       q->boundary_rq = NULL;
-               }
-
-               if (rq->cmd_flags & REQ_DONTPREP)
-                       break;
-
-               if (q->dma_drain_size && rq->data_len) {
-                       /*
-                        * make sure space for the drain appears we
-                        * know we can do this because max_hw_segments
-                        * has been adjusted to be one fewer than the
-                        * device can handle
-                        */
-                       rq->nr_phys_segments++;
-               }
-
-               if (!q->prep_rq_fn)
-                       break;
-
-               ret = q->prep_rq_fn(q, rq);
-               if (ret == BLKPREP_OK) {
-                       break;
-               } else if (ret == BLKPREP_DEFER) {
-                       /*
-                        * the request may have been (partially) prepped.
-                        * we need to keep this request in the front to
-                        * avoid resource deadlock.  REQ_STARTED will
-                        * prevent other fs requests from passing this one.
-                        */
-                       if (q->dma_drain_size && rq->data_len &&
-                           !(rq->cmd_flags & REQ_DONTPREP)) {
-                               /*
-                                * remove the space for the drain we added
-                                * so that we don't add it again
-                                */
-                               --rq->nr_phys_segments;
-                       }
-
-                       rq = NULL;
-                       break;
-               } else if (ret == BLKPREP_KILL) {
-                       rq->cmd_flags |= REQ_QUIET;
-                       __blk_end_request(rq, -EIO, blk_rq_bytes(rq));
-               } else {
-                       printk(KERN_ERR "%s: bad return=%d\n", __func__, ret);
-                       break;
-               }
-       }
-
-       return rq;
-}
-EXPORT_SYMBOL(elv_next_request);
-
-void elv_dequeue_request(struct request_queue *q, struct request *rq)
-{
-       BUG_ON(list_empty(&rq->queuelist));
-       BUG_ON(ELV_ON_HASH(rq));
-
-       list_del_init(&rq->queuelist);
-
-       /*
-        * the time frame between a request being removed from the lists
-        * and to it is freed is accounted as io that is in progress at
-        * the driver side.
-        */
-       if (blk_account_rq(rq))
-               q->in_flight++;
-}
-
 int elv_queue_empty(struct request_queue *q)
 {
        struct elevator_queue *e = q->elevator;
@@ -939,7 +809,12 @@ void elv_abort_queue(struct request_queue *q)
                rq = list_entry_rq(q->queue_head.next);
                rq->cmd_flags |= REQ_QUIET;
                trace_block_rq_abort(q, rq);
-               __blk_end_request(rq, -EIO, blk_rq_bytes(rq));
+               /*
+                * Mark this request as started so we don't trigger
+                * any debug logic in the end I/O path.
+                */
+               blk_start_request(rq);
+               __blk_end_request_all(rq, -EIO);
        }
 }
 EXPORT_SYMBOL(elv_abort_queue);
@@ -952,7 +827,7 @@ void elv_completed_request(struct request_queue *q, struct request *rq)
         * request is released from the driver, io must be done
         */
        if (blk_account_rq(rq)) {
-               q->in_flight--;
+               q->in_flight[rq_is_sync(rq)]--;
                if (blk_sorted_rq(rq) && e->ops->elevator_completed_req_fn)
                        e->ops->elevator_completed_req_fn(q, rq);
        }
@@ -967,11 +842,11 @@ void elv_completed_request(struct request_queue *q, struct request *rq)
                if (!list_empty(&q->queue_head))
                        next = list_entry_rq(q->queue_head.next);
 
-               if (!q->in_flight &&
+               if (!queue_in_flight(q) &&
                    blk_ordered_cur_seq(q) == QUEUE_ORDSEQ_DRAIN &&
                    (!next || blk_ordered_req_seq(next) > QUEUE_ORDSEQ_DRAIN)) {
                        blk_ordered_complete_seq(q, QUEUE_ORDSEQ_DRAIN, 0);
-                       blk_start_queueing(q);
+                       __blk_run_queue(q);
                }
        }
 }
@@ -1179,6 +1054,9 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name,
        char elevator_name[ELV_NAME_MAX];
        struct elevator_type *e;
 
+       if (!q->elevator)
+               return count;
+
        strlcpy(elevator_name, name, sizeof(elevator_name));
        strstrip(elevator_name);
 
@@ -1202,10 +1080,15 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name,
 ssize_t elv_iosched_show(struct request_queue *q, char *name)
 {
        struct elevator_queue *e = q->elevator;
-       struct elevator_type *elv = e->elevator_type;
+       struct elevator_type *elv;
        struct elevator_type *__e;
        int len = 0;
 
+       if (!q->elevator)
+               return sprintf(name, "none\n");
+
+       elv = e->elevator_type;
+
        spin_lock(&elv_list_lock);
        list_for_each_entry(__e, &elv_list, list) {
                if (!strcmp(elv->elevator_name, __e->elevator_name))
index 1a4916e01732b68ebb9af5ff2fd831c78057d910..fe7ccc0a618f35e21ed7fbbe19ae49665270d498 100644 (file)
@@ -852,11 +852,21 @@ static ssize_t disk_capability_show(struct device *dev,
        return sprintf(buf, "%x\n", disk->flags);
 }
 
+static ssize_t disk_alignment_offset_show(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       struct gendisk *disk = dev_to_disk(dev);
+
+       return sprintf(buf, "%d\n", queue_alignment_offset(disk->queue));
+}
+
 static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
 static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL);
 static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
 static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL);
 static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
+static DEVICE_ATTR(alignment_offset, S_IRUGO, disk_alignment_offset_show, NULL);
 static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
 static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
 #ifdef CONFIG_FAIL_MAKE_REQUEST
@@ -875,6 +885,7 @@ static struct attribute *disk_attrs[] = {
        &dev_attr_removable.attr,
        &dev_attr_ro.attr,
        &dev_attr_size.attr,
+       &dev_attr_alignment_offset.attr,
        &dev_attr_capability.attr,
        &dev_attr_stat.attr,
 #ifdef CONFIG_FAIL_MAKE_REQUEST
index ad474d4bbccee0232303c24ae381ade156ae44aa..500e4c73cc52ba3a36b844c9e97404508ccf4b9b 100644 (file)
@@ -152,10 +152,10 @@ static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
                bio->bi_private = &wait;
                bio->bi_sector = start;
 
-               if (len > q->max_hw_sectors) {
-                       bio->bi_size = q->max_hw_sectors << 9;
-                       len -= q->max_hw_sectors;
-                       start += q->max_hw_sectors;
+               if (len > queue_max_hw_sectors(q)) {
+                       bio->bi_size = queue_max_hw_sectors(q) << 9;
+                       len -= queue_max_hw_sectors(q);
+                       start += queue_max_hw_sectors(q);
                } else {
                        bio->bi_size = len << 9;
                        len = 0;
@@ -311,9 +311,9 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
        case BLKBSZGET: /* get the logical block size (cf. BLKSSZGET) */
                return put_int(arg, block_size(bdev));
        case BLKSSZGET: /* get block device hardware sector size */
-               return put_int(arg, bdev_hardsect_size(bdev));
+               return put_int(arg, bdev_logical_block_size(bdev));
        case BLKSECTGET:
-               return put_ushort(arg, bdev_get_queue(bdev)->max_sectors);
+               return put_ushort(arg, queue_max_sectors(bdev_get_queue(bdev)));
        case BLKRASET:
        case BLKFRASET:
                if(!capable(CAP_SYS_ADMIN))
index 82a0ca2f672901a8fab6442ae8a3662bedd7e6b8..5f8e798ede4ee6d7c479bce1ee36f5488b717cc9 100644 (file)
@@ -75,7 +75,7 @@ static int sg_set_timeout(struct request_queue *q, int __user *p)
 
 static int sg_get_reserved_size(struct request_queue *q, int __user *p)
 {
-       unsigned val = min(q->sg_reserved_size, q->max_sectors << 9);
+       unsigned val = min(q->sg_reserved_size, queue_max_sectors(q) << 9);
 
        return put_user(val, p);
 }
@@ -89,8 +89,8 @@ static int sg_set_reserved_size(struct request_queue *q, int __user *p)
 
        if (size < 0)
                return -EINVAL;
-       if (size > (q->max_sectors << 9))
-               size = q->max_sectors << 9;
+       if (size > (queue_max_sectors(q) << 9))
+               size = queue_max_sectors(q) << 9;
 
        q->sg_reserved_size = size;
        return 0;
@@ -230,7 +230,7 @@ static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
        hdr->info = 0;
        if (hdr->masked_status || hdr->host_status || hdr->driver_status)
                hdr->info |= SG_INFO_CHECK;
-       hdr->resid = rq->data_len;
+       hdr->resid = rq->resid_len;
        hdr->sb_len_wr = 0;
 
        if (rq->sense_len && hdr->sbp) {
@@ -264,7 +264,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
        if (hdr->cmd_len > BLK_MAX_CDB)
                return -EINVAL;
 
-       if (hdr->dxfer_len > (q->max_hw_sectors << 9))
+       if (hdr->dxfer_len > (queue_max_hw_sectors(q) << 9))
                return -EIO;
 
        if (hdr->dxfer_len)
@@ -500,9 +500,6 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk,
 
        rq = blk_get_request(q, WRITE, __GFP_WAIT);
        rq->cmd_type = REQ_TYPE_BLOCK_PC;
-       rq->data = NULL;
-       rq->data_len = 0;
-       rq->extra_len = 0;
        rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
        rq->cmd[0] = cmd;
        rq->cmd[4] = data;
index 51b9f8280f887cfd6649a39446e7e081d52fe3b6..2faa9e2ac89331b9c46c1de0de560a0225ce88e2 100644 (file)
@@ -401,7 +401,8 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
                /* Interrupt Line values above 0xF are forbidden */
                if (dev->irq > 0 && (dev->irq <= 0xF)) {
                        printk(" - using IRQ %d\n", dev->irq);
-                       acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE,
+                       acpi_register_gsi(&dev->dev, dev->irq,
+                                         ACPI_LEVEL_SENSITIVE,
                                          ACPI_ACTIVE_LOW);
                        return 0;
                } else {
@@ -410,7 +411,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
                }
        }
 
-       rc = acpi_register_gsi(gsi, triggering, polarity);
+       rc = acpi_register_gsi(&dev->dev, gsi, triggering, polarity);
        if (rc < 0) {
                dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n",
                         pin_name(pin));
index 342316064e9ffe88b8962910908c345593c9ef1a..d0dfeef55db58444d5eeb979ab97f1e1628112c8 100644 (file)
@@ -1084,7 +1084,7 @@ static int atapi_drain_needed(struct request *rq)
        if (likely(!blk_pc_request(rq)))
                return 0;
 
-       if (!rq->data_len || (rq->cmd_flags & REQ_RW))
+       if (!blk_rq_bytes(rq) || (rq->cmd_flags & REQ_RW))
                return 0;
 
        return atapi_cmd_type(rq->cmd[0]) == ATAPI_MISC;
index f22ed6cc69f286f916c9c064871ffaad77babeca..668dc234b8e22d5b09950950914398d6f1f61766 100644 (file)
@@ -3321,7 +3321,7 @@ static int DAC960_process_queue(DAC960_Controller_T *Controller, struct request_
        DAC960_Command_T *Command;
 
    while(1) {
-       Request = elv_next_request(req_q);
+       Request = blk_peek_request(req_q);
        if (!Request)
                return 1;
 
@@ -3338,10 +3338,10 @@ static int DAC960_process_queue(DAC960_Controller_T *Controller, struct request_
        }
        Command->Completion = Request->end_io_data;
        Command->LogicalDriveNumber = (long)Request->rq_disk->private_data;
-       Command->BlockNumber = Request->sector;
-       Command->BlockCount = Request->nr_sectors;
+       Command->BlockNumber = blk_rq_pos(Request);
+       Command->BlockCount = blk_rq_sectors(Request);
        Command->Request = Request;
-       blkdev_dequeue_request(Request);
+       blk_start_request(Request);
        Command->SegmentCount = blk_rq_map_sg(req_q,
                  Command->Request, Command->cmd_sglist);
        /* pci_map_sg MAY change the value of SegCount */
@@ -3431,7 +3431,7 @@ static void DAC960_queue_partial_rw(DAC960_Command_T *Command)
    * successfully as possible.
    */
   Command->SegmentCount = 1;
-  Command->BlockNumber = Request->sector;
+  Command->BlockNumber = blk_rq_pos(Request);
   Command->BlockCount = 1;
   DAC960_QueueReadWriteCommand(Command);
   return;
index ddea8e485cc94dbc6ed9acddfd9231a26896bfca..f42fa50d35506276722ac6b21417468f847ba6c7 100644 (file)
@@ -412,7 +412,7 @@ config ATA_OVER_ETH
 
 config MG_DISK
        tristate "mGine mflash, gflash support"
-       depends on ARM && ATA && GPIOLIB
+       depends on ARM && GPIOLIB
        help
          mGine mFlash(gFlash) block device driver
 
index 8df436ff7068b4840bdbcf610e357797ae387ae5..9c6e5b0fe894f9e6af94a50b87a2ec2b2f04a470 100644 (file)
@@ -112,8 +112,6 @@ module_param(fd_def_df0, ulong, 0);
 MODULE_LICENSE("GPL");
 
 static struct request_queue *floppy_queue;
-#define QUEUE (floppy_queue)
-#define CURRENT elv_next_request(floppy_queue)
 
 /*
  *  Macros
@@ -1335,64 +1333,60 @@ static int get_track(int drive, int track)
 
 static void redo_fd_request(void)
 {
+       struct request *rq;
        unsigned int cnt, block, track, sector;
        int drive;
        struct amiga_floppy_struct *floppy;
        char *data;
        unsigned long flags;
+       int err;
 
- repeat:
-       if (!CURRENT) {
+next_req:
+       rq = blk_fetch_request(floppy_queue);
+       if (!rq) {
                /* Nothing left to do */
                return;
        }
 
-       floppy = CURRENT->rq_disk->private_data;
+       floppy = rq->rq_disk->private_data;
        drive = floppy - unit;
 
+next_segment:
        /* Here someone could investigate to be more efficient */
-       for (cnt = 0; cnt < CURRENT->current_nr_sectors; cnt++) { 
+       for (cnt = 0, err = 0; cnt < blk_rq_cur_sectors(rq); cnt++) {
 #ifdef DEBUG
                printk("fd: sector %ld + %d requested for %s\n",
-                      CURRENT->sector,cnt,
-                      (rq_data_dir(CURRENT) == READ) ? "read" : "write");
+                      blk_rq_pos(rq), cnt,
+                      (rq_data_dir(rq) == READ) ? "read" : "write");
 #endif
-               block = CURRENT->sector + cnt;
+               block = blk_rq_pos(rq) + cnt;
                if ((int)block > floppy->blocks) {
-                       end_request(CURRENT, 0);
-                       goto repeat;
+                       err = -EIO;
+                       break;
                }
 
                track = block / (floppy->dtype->sects * floppy->type->sect_mult);
                sector = block % (floppy->dtype->sects * floppy->type->sect_mult);
-               data = CURRENT->buffer + 512 * cnt;
+               data = rq->buffer + 512 * cnt;
 #ifdef DEBUG
                printk("access to track %d, sector %d, with buffer at "
                       "0x%08lx\n", track, sector, data);
 #endif
 
-               if ((rq_data_dir(CURRENT) != READ) && (rq_data_dir(CURRENT) != WRITE)) {
-                       printk(KERN_WARNING "do_fd_request: unknown command\n");
-                       end_request(CURRENT, 0);
-                       goto repeat;
-               }
                if (get_track(drive, track) == -1) {
-                       end_request(CURRENT, 0);
-                       goto repeat;
+                       err = -EIO;
+                       break;
                }
 
-               switch (rq_data_dir(CURRENT)) {
-               case READ:
+               if (rq_data_dir(rq) == READ) {
                        memcpy(data, floppy->trackbuf + sector * 512, 512);
-                       break;
-
-               case WRITE:
+               } else {
                        memcpy(floppy->trackbuf + sector * 512, data, 512);
 
                        /* keep the drive spinning while writes are scheduled */
                        if (!fd_motor_on(drive)) {
-                               end_request(CURRENT, 0);
-                               goto repeat;
+                               err = -EIO;
+                               break;
                        }
                        /*
                         * setup a callback to write the track buffer
@@ -1404,14 +1398,12 @@ static void redo_fd_request(void)
                        /* reset the timer */
                        mod_timer (flush_track_timer + drive, jiffies + 1);
                        local_irq_restore(flags);
-                       break;
                }
        }
-       CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
-       CURRENT->sector += CURRENT->current_nr_sectors;
 
-       end_request(CURRENT, 1);
-       goto repeat;
+       if (__blk_end_request_cur(rq, err))
+               goto next_segment;
+       goto next_req;
 }
 
 static void do_fd_request(struct request_queue * q)
index 4234c11c1e4cfe34592c9830eca7d2a68400b052..f5e7180d7f47d050ed0e39a37ad748054658b52b 100644 (file)
@@ -79,9 +79,7 @@
 #undef DEBUG
 
 static struct request_queue *floppy_queue;
-
-#define QUEUE (floppy_queue)
-#define CURRENT elv_next_request(floppy_queue)
+static struct request *fd_request;
 
 /* Disk types: DD, HD, ED */
 static struct atari_disk_type {
@@ -376,6 +374,12 @@ static DEFINE_TIMER(readtrack_timer, fd_readtrack_check, 0, 0);
 static DEFINE_TIMER(timeout_timer, fd_times_out, 0, 0);
 static DEFINE_TIMER(fd_timer, check_change, 0, 0);
        
+static void fd_end_request_cur(int err)
+{
+       if (!__blk_end_request_cur(fd_request, err))
+               fd_request = NULL;
+}
+
 static inline void start_motor_off_timer(void)
 {
        mod_timer(&motor_off_timer, jiffies + FD_MOTOR_OFF_DELAY);
@@ -606,15 +610,15 @@ static void fd_error( void )
                return;
        }
 
-       if (!CURRENT)
+       if (!fd_request)
                return;
 
-       CURRENT->errors++;
-       if (CURRENT->errors >= MAX_ERRORS) {
+       fd_request->errors++;
+       if (fd_request->errors >= MAX_ERRORS) {
                printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive );
-               end_request(CURRENT, 0);
+               fd_end_request_cur(-EIO);
        }
-       else if (CURRENT->errors == RECALIBRATE_ERRORS) {
+       else if (fd_request->errors == RECALIBRATE_ERRORS) {
                printk(KERN_WARNING "fd%d: recalibrating\n", SelectedDrive );
                if (SelectedDrive != -1)
                        SUD.track = -1;
@@ -725,16 +729,14 @@ static void do_fd_action( int drive )
            if (IS_BUFFERED( drive, ReqSide, ReqTrack )) {
                if (ReqCmd == READ) {
                    copy_buffer( SECTOR_BUFFER(ReqSector), ReqData );
-                   if (++ReqCnt < CURRENT->current_nr_sectors) {
+                   if (++ReqCnt < blk_rq_cur_sectors(fd_request)) {
                        /* read next sector */
                        setup_req_params( drive );
                        goto repeat;
                    }
                    else {
                        /* all sectors finished */
-                       CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
-                       CURRENT->sector += CURRENT->current_nr_sectors;
-                       end_request(CURRENT, 1);
+                       fd_end_request_cur(0);
                        redo_fd_request();
                        return;
                    }
@@ -1132,16 +1134,14 @@ static void fd_rwsec_done1(int status)
                }
        }
   
-       if (++ReqCnt < CURRENT->current_nr_sectors) {
+       if (++ReqCnt < blk_rq_cur_sectors(fd_request)) {
                /* read next sector */
                setup_req_params( SelectedDrive );
                do_fd_action( SelectedDrive );
        }
        else {
                /* all sectors finished */
-               CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
-               CURRENT->sector += CURRENT->current_nr_sectors;
-               end_request(CURRENT, 1);
+               fd_end_request_cur(0);
                redo_fd_request();
        }
        return;
@@ -1382,7 +1382,7 @@ static void setup_req_params( int drive )
        ReqData = ReqBuffer + 512 * ReqCnt;
 
        if (UseTrackbuffer)
-               read_track = (ReqCmd == READ && CURRENT->errors == 0);
+               read_track = (ReqCmd == READ && fd_request->errors == 0);
        else
                read_track = 0;
 
@@ -1396,25 +1396,27 @@ static void redo_fd_request(void)
        int drive, type;
        struct atari_floppy_struct *floppy;
 
-       DPRINT(("redo_fd_request: CURRENT=%p dev=%s CURRENT->sector=%ld\n",
-               CURRENT, CURRENT ? CURRENT->rq_disk->disk_name : "",
-               CURRENT ? CURRENT->sector : 0 ));
+       DPRINT(("redo_fd_request: fd_request=%p dev=%s fd_request->sector=%ld\n",
+               fd_request, fd_request ? fd_request->rq_disk->disk_name : "",
+               fd_request ? blk_rq_pos(fd_request) : 0 ));
 
        IsFormatting = 0;
 
 repeat:
+       if (!fd_request) {
+               fd_request = blk_fetch_request(floppy_queue);
+               if (!fd_request)
+                       goto the_end;
+       }
 
-       if (!CURRENT)
-               goto the_end;
-
-       floppy = CURRENT->rq_disk->private_data;
+       floppy = fd_request->rq_disk->private_data;
        drive = floppy - unit;
        type = floppy->type;
        
        if (!UD.connected) {
                /* drive not connected */
                printk(KERN_ERR "Unknown Device: fd%d\n", drive );
-               end_request(CURRENT, 0);
+               fd_end_request_cur(-EIO);
                goto repeat;
        }
                
@@ -1430,12 +1432,12 @@ repeat:
                /* user supplied disk type */
                if (--type >= NUM_DISK_MINORS) {
                        printk(KERN_WARNING "fd%d: invalid disk format", drive );
-                       end_request(CURRENT, 0);
+                       fd_end_request_cur(-EIO);
                        goto repeat;
                }
                if (minor2disktype[type].drive_types > DriveType)  {
                        printk(KERN_WARNING "fd%d: unsupported disk format", drive );
-                       end_request(CURRENT, 0);
+                       fd_end_request_cur(-EIO);
                        goto repeat;
                }
                type = minor2disktype[type].index;
@@ -1444,8 +1446,8 @@ repeat:
                UD.autoprobe = 0;
        }
        
-       if (CURRENT->sector + 1 > UDT->blocks) {
-               end_request(CURRENT, 0);
+       if (blk_rq_pos(fd_request) + 1 > UDT->blocks) {
+               fd_end_request_cur(-EIO);
                goto repeat;
        }
 
@@ -1453,9 +1455,9 @@ repeat:
        del_timer( &motor_off_timer );
                
        ReqCnt = 0;
-       ReqCmd = rq_data_dir(CURRENT);
-       ReqBlock = CURRENT->sector;
-       ReqBuffer = CURRENT->buffer;
+       ReqCmd = rq_data_dir(fd_request);
+       ReqBlock = blk_rq_pos(fd_request);
+       ReqBuffer = fd_request->buffer;
        setup_req_params( drive );
        do_fd_action( drive );
 
index 5f7e64ba87e500030fdb53cadf4c1c51b9941e10..4bf8705b3acede5f1558e1f44c168abe5be73d3f 100644 (file)
@@ -407,12 +407,7 @@ static int __init ramdisk_size(char *str)
        rd_size = simple_strtol(str, NULL, 0);
        return 1;
 }
-static int __init ramdisk_size2(char *str)
-{
-       return ramdisk_size(str);
-}
-__setup("ramdisk=", ramdisk_size);
-__setup("ramdisk_size=", ramdisk_size2);
+__setup("ramdisk_size=", ramdisk_size);
 #endif
 
 /*
index 4d4d5e0d3fa64af15faf87a3a78c2a3b0396ef9c..b22cec97ea194e148427f998a5c310bc3eedf262 100644 (file)
@@ -180,11 +180,13 @@ static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *,
                                           __u32);
 static void start_io(ctlr_info_t *h);
 static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size,
-                  unsigned int use_unit_num, unsigned int log_unit,
                   __u8 page_code, unsigned char *scsi3addr, int cmd_type);
 static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
-                          unsigned int use_unit_num, unsigned int log_unit,
-                          __u8 page_code, int cmd_type);
+                       __u8 page_code, unsigned char scsi3addr[],
+                       int cmd_type);
+static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c,
+       int attempt_retry);
+static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c);
 
 static void fail_all_cmds(unsigned long ctlr);
 static int scan_thread(void *data);
@@ -437,6 +439,194 @@ static void __devinit cciss_procinit(int i)
 }
 #endif                         /* CONFIG_PROC_FS */
 
+#define MAX_PRODUCT_NAME_LEN 19
+
+#define to_hba(n) container_of(n, struct ctlr_info, dev)
+#define to_drv(n) container_of(n, drive_info_struct, dev)
+
+static struct device_type cciss_host_type = {
+       .name           = "cciss_host",
+};
+
+static ssize_t dev_show_unique_id(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       drive_info_struct *drv = to_drv(dev);
+       struct ctlr_info *h = to_hba(drv->dev.parent);
+       __u8 sn[16];
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       if (h->busy_configuring)
+               ret = -EBUSY;
+       else
+               memcpy(sn, drv->serial_no, sizeof(sn));
+       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+
+       if (ret)
+               return ret;
+       else
+               return snprintf(buf, 16 * 2 + 2,
+                               "%02X%02X%02X%02X%02X%02X%02X%02X"
+                               "%02X%02X%02X%02X%02X%02X%02X%02X\n",
+                               sn[0], sn[1], sn[2], sn[3],
+                               sn[4], sn[5], sn[6], sn[7],
+                               sn[8], sn[9], sn[10], sn[11],
+                               sn[12], sn[13], sn[14], sn[15]);
+}
+DEVICE_ATTR(unique_id, S_IRUGO, dev_show_unique_id, NULL);
+
+static ssize_t dev_show_vendor(struct device *dev,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       drive_info_struct *drv = to_drv(dev);
+       struct ctlr_info *h = to_hba(drv->dev.parent);
+       char vendor[VENDOR_LEN + 1];
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       if (h->busy_configuring)
+               ret = -EBUSY;
+       else
+               memcpy(vendor, drv->vendor, VENDOR_LEN + 1);
+       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+
+       if (ret)
+               return ret;
+       else
+               return snprintf(buf, sizeof(vendor) + 1, "%s\n", drv->vendor);
+}
+DEVICE_ATTR(vendor, S_IRUGO, dev_show_vendor, NULL);
+
+static ssize_t dev_show_model(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       drive_info_struct *drv = to_drv(dev);
+       struct ctlr_info *h = to_hba(drv->dev.parent);
+       char model[MODEL_LEN + 1];
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       if (h->busy_configuring)
+               ret = -EBUSY;
+       else
+               memcpy(model, drv->model, MODEL_LEN + 1);
+       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+
+       if (ret)
+               return ret;
+       else
+               return snprintf(buf, sizeof(model) + 1, "%s\n", drv->model);
+}
+DEVICE_ATTR(model, S_IRUGO, dev_show_model, NULL);
+
+static ssize_t dev_show_rev(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       drive_info_struct *drv = to_drv(dev);
+       struct ctlr_info *h = to_hba(drv->dev.parent);
+       char rev[REV_LEN + 1];
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       if (h->busy_configuring)
+               ret = -EBUSY;
+       else
+               memcpy(rev, drv->rev, REV_LEN + 1);
+       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+
+       if (ret)
+               return ret;
+       else
+               return snprintf(buf, sizeof(rev) + 1, "%s\n", drv->rev);
+}
+DEVICE_ATTR(rev, S_IRUGO, dev_show_rev, NULL);
+
+static struct attribute *cciss_dev_attrs[] = {
+       &dev_attr_unique_id.attr,
+       &dev_attr_model.attr,
+       &dev_attr_vendor.attr,
+       &dev_attr_rev.attr,
+       NULL
+};
+
+static struct attribute_group cciss_dev_attr_group = {
+       .attrs = cciss_dev_attrs,
+};
+
+static struct attribute_group *cciss_dev_attr_groups[] = {
+       &cciss_dev_attr_group,
+       NULL
+};
+
+static struct device_type cciss_dev_type = {
+       .name           = "cciss_device",
+       .groups         = cciss_dev_attr_groups,
+};
+
+static struct bus_type cciss_bus_type = {
+       .name           = "cciss",
+};
+
+
+/*
+ * Initialize sysfs entry for each controller.  This sets up and registers
+ * the 'cciss#' directory for each individual controller under
+ * /sys/bus/pci/devices/<dev>/.
+ */
+static int cciss_create_hba_sysfs_entry(struct ctlr_info *h)
+{
+       device_initialize(&h->dev);
+       h->dev.type = &cciss_host_type;
+       h->dev.bus = &cciss_bus_type;
+       dev_set_name(&h->dev, "%s", h->devname);
+       h->dev.parent = &h->pdev->dev;
+
+       return device_add(&h->dev);
+}
+
+/*
+ * Remove sysfs entries for an hba.
+ */
+static void cciss_destroy_hba_sysfs_entry(struct ctlr_info *h)
+{
+       device_del(&h->dev);
+}
+
+/*
+ * Initialize sysfs for each logical drive.  This sets up and registers
+ * the 'c#d#' directory for each individual logical drive under
+ * /sys/bus/pci/devices/<dev/ccis#/. We also create a link from
+ * /sys/block/cciss!c#d# to this entry.
+ */
+static int cciss_create_ld_sysfs_entry(struct ctlr_info *h,
+                                      drive_info_struct *drv,
+                                      int drv_index)
+{
+       device_initialize(&drv->dev);
+       drv->dev.type = &cciss_dev_type;
+       drv->dev.bus = &cciss_bus_type;
+       dev_set_name(&drv->dev, "c%dd%d", h->ctlr, drv_index);
+       drv->dev.parent = &h->dev;
+       return device_add(&drv->dev);
+}
+
+/*
+ * Remove sysfs entries for a logical drive.
+ */
+static void cciss_destroy_ld_sysfs_entry(drive_info_struct *drv)
+{
+       device_del(&drv->dev);
+}
+
 /*
  * For operations that cannot sleep, a command block is allocated at init,
  * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
@@ -1299,7 +1489,6 @@ static void cciss_softirq_done(struct request *rq)
 {
        CommandList_struct *cmd = rq->completion_data;
        ctlr_info_t *h = hba[cmd->ctlr];
-       unsigned int nr_bytes;
        unsigned long flags;
        u64bit temp64;
        int i, ddir;
@@ -1321,15 +1510,11 @@ static void cciss_softirq_done(struct request *rq)
        printk("Done with %p\n", rq);
 #endif                         /* CCISS_DEBUG */
 
-       /*
-        * Store the full size and set the residual count for pc requests
-        */
-       nr_bytes = blk_rq_bytes(rq);
+       /* set the residual count for pc requests */
        if (blk_pc_request(rq))
-               rq->data_len = cmd->err_info->ResidualCnt;
+               rq->resid_len = cmd->err_info->ResidualCnt;
 
-       if (blk_end_request(rq, (rq->errors == 0) ? 0 : -EIO, nr_bytes))
-               BUG();
+       blk_end_request_all(rq, (rq->errors == 0) ? 0 : -EIO);
 
        spin_lock_irqsave(&h->lock, flags);
        cmd_free(h, cmd, 1);
@@ -1337,6 +1522,56 @@ static void cciss_softirq_done(struct request *rq)
        spin_unlock_irqrestore(&h->lock, flags);
 }
 
+static void log_unit_to_scsi3addr(ctlr_info_t *h, unsigned char scsi3addr[],
+       uint32_t log_unit)
+{
+       log_unit = h->drv[log_unit].LunID & 0x03fff;
+       memset(&scsi3addr[4], 0, 4);
+       memcpy(&scsi3addr[0], &log_unit, 4);
+       scsi3addr[3] |= 0x40;
+}
+
+/* This function gets the SCSI vendor, model, and revision of a logical drive
+ * via the inquiry page 0.  Model, vendor, and rev are set to empty strings if
+ * they cannot be read.
+ */
+static void cciss_get_device_descr(int ctlr, int logvol, int withirq,
+                                  char *vendor, char *model, char *rev)
+{
+       int rc;
+       InquiryData_struct *inq_buf;
+       unsigned char scsi3addr[8];
+
+       *vendor = '\0';
+       *model = '\0';
+       *rev = '\0';
+
+       inq_buf = kzalloc(sizeof(InquiryData_struct), GFP_KERNEL);
+       if (!inq_buf)
+               return;
+
+       log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
+       if (withirq)
+               rc = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buf,
+                            sizeof(InquiryData_struct), 0,
+                               scsi3addr, TYPE_CMD);
+       else
+               rc = sendcmd(CISS_INQUIRY, ctlr, inq_buf,
+                            sizeof(InquiryData_struct), 0,
+                               scsi3addr, TYPE_CMD);
+       if (rc == IO_OK) {
+               memcpy(vendor, &inq_buf->data_byte[8], VENDOR_LEN);
+               vendor[VENDOR_LEN] = '\0';
+               memcpy(model, &inq_buf->data_byte[16], MODEL_LEN);
+               model[MODEL_LEN] = '\0';
+               memcpy(rev, &inq_buf->data_byte[32], REV_LEN);
+               rev[REV_LEN] = '\0';
+       }
+
+       kfree(inq_buf);
+       return;
+}
+
 /* This function gets the serial number of a logical drive via
  * inquiry page 0x83.  Serial no. is 16 bytes.  If the serial
  * number cannot be had, for whatever reason, 16 bytes of 0xff
@@ -1348,6 +1583,7 @@ static void cciss_get_serial_no(int ctlr, int logvol, int withirq,
 #define PAGE_83_INQ_BYTES 64
        int rc;
        unsigned char *buf;
+       unsigned char scsi3addr[8];
 
        if (buflen > 16)
                buflen = 16;
@@ -1356,12 +1592,13 @@ static void cciss_get_serial_no(int ctlr, int logvol, int withirq,
        if (!buf)
                return;
        memset(serial_no, 0, buflen);
+       log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
        if (withirq)
                rc = sendcmd_withirq(CISS_INQUIRY, ctlr, buf,
-                       PAGE_83_INQ_BYTES, 1, logvol, 0x83, TYPE_CMD);
+                       PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD);
        else
                rc = sendcmd(CISS_INQUIRY, ctlr, buf,
-                       PAGE_83_INQ_BYTES, 1, logvol, 0x83, NULL, TYPE_CMD);
+                       PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD);
        if (rc == IO_OK)
                memcpy(serial_no, &buf[8], buflen);
        kfree(buf);
@@ -1377,7 +1614,7 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
        disk->first_minor = drv_index << NWD_SHIFT;
        disk->fops = &cciss_fops;
        disk->private_data = &h->drv[drv_index];
-       disk->driverfs_dev = &h->pdev->dev;
+       disk->driverfs_dev = &h->drv[drv_index].dev;
 
        /* Set up queue information */
        blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask);
@@ -1394,8 +1631,8 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
 
        disk->queue->queuedata = h;
 
-       blk_queue_hardsect_size(disk->queue,
-                               h->drv[drv_index].block_size);
+       blk_queue_logical_block_size(disk->queue,
+                                    h->drv[drv_index].block_size);
 
        /* Make sure all queue data is written out before */
        /* setting h->drv[drv_index].queue, as setting this */
@@ -1468,6 +1705,8 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
        drvinfo->block_size = block_size;
        drvinfo->nr_blocks = total_size + 1;
 
+       cciss_get_device_descr(ctlr, drv_index, 1, drvinfo->vendor,
+                               drvinfo->model, drvinfo->rev);
        cciss_get_serial_no(ctlr, drv_index, 1, drvinfo->serial_no,
                        sizeof(drvinfo->serial_no));
 
@@ -1517,6 +1756,9 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
        h->drv[drv_index].cylinders = drvinfo->cylinders;
        h->drv[drv_index].raid_level = drvinfo->raid_level;
        memcpy(h->drv[drv_index].serial_no, drvinfo->serial_no, 16);
+       memcpy(h->drv[drv_index].vendor, drvinfo->vendor, VENDOR_LEN + 1);
+       memcpy(h->drv[drv_index].model, drvinfo->model, MODEL_LEN + 1);
+       memcpy(h->drv[drv_index].rev, drvinfo->rev, REV_LEN + 1);
 
        ++h->num_luns;
        disk = h->gendisk[drv_index];
@@ -1591,6 +1833,8 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node)
                }
        }
        h->drv[drv_index].LunID = lunid;
+       if (cciss_create_ld_sysfs_entry(h, &h->drv[drv_index], drv_index))
+               goto err_free_disk;
 
        /* Don't need to mark this busy because nobody */
        /* else knows about this disk yet to contend */
@@ -1598,6 +1842,11 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node)
        h->drv[drv_index].busy_configuring = 0;
        wmb();
        return drv_index;
+
+err_free_disk:
+       put_disk(h->gendisk[drv_index]);
+       h->gendisk[drv_index] = NULL;
+       return -1;
 }
 
 /* This is for the special case of a controller which
@@ -1668,8 +1917,8 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
                goto mem_msg;
 
        return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
-                                     sizeof(ReportLunData_struct), 0,
-                                     0, 0, TYPE_CMD);
+                                     sizeof(ReportLunData_struct),
+                                     0, CTLR_LUNID, TYPE_CMD);
 
        if (return_code == IO_OK)
                listlength = be32_to_cpu(*(__be32 *) ld_buff->LUNListLength);
@@ -1718,6 +1967,7 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
                        h->drv[i].busy_configuring = 1;
                        spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
                        return_code = deregister_disk(h, i, 1);
+                       cciss_destroy_ld_sysfs_entry(&h->drv[i]);
                        h->drv[i].busy_configuring = 0;
                }
        }
@@ -1877,11 +2127,9 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,
        return 0;
 }
 
-static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num,     /* 0: address the controller,
-                                                                                                                          1: address logical volume log_unit,
-                                                                                                                          2: periph device address is scsi3addr */
-                   unsigned int log_unit, __u8 page_code,
-                   unsigned char *scsi3addr, int cmd_type)
+static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
+               size_t size, __u8 page_code, unsigned char *scsi3addr,
+               int cmd_type)
 {
        ctlr_info_t *h = hba[ctlr];
        u64bit buff_dma_handle;
@@ -1897,27 +2145,12 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
                c->Header.SGTotal = 0;
        }
        c->Header.Tag.lower = c->busaddr;
+       memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8);
 
        c->Request.Type.Type = cmd_type;
        if (cmd_type == TYPE_CMD) {
                switch (cmd) {
                case CISS_INQUIRY:
-                       /* If the logical unit number is 0 then, this is going
-                          to controller so It's a physical command
-                          mode = 0 target = 0.  So we have nothing to write.
-                          otherwise, if use_unit_num == 1,
-                          mode = 1(volume set addressing) target = LUNID
-                          otherwise, if use_unit_num == 2,
-                          mode = 0(periph dev addr) target = scsi3addr */
-                       if (use_unit_num == 1) {
-                               c->Header.LUN.LogDev.VolId =
-                                   h->drv[log_unit].LunID;
-                               c->Header.LUN.LogDev.Mode = 1;
-                       } else if (use_unit_num == 2) {
-                               memcpy(c->Header.LUN.LunAddrBytes, scsi3addr,
-                                      8);
-                               c->Header.LUN.LogDev.Mode = 0;
-                       }
                        /* are we trying to read a vital product page */
                        if (page_code != 0) {
                                c->Request.CDB[1] = 0x01;
@@ -1947,8 +2180,6 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
                        break;
 
                case CCISS_READ_CAPACITY:
-                       c->Header.LUN.LogDev.VolId = h->drv[log_unit].LunID;
-                       c->Header.LUN.LogDev.Mode = 1;
                        c->Request.CDBLen = 10;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
                        c->Request.Type.Direction = XFER_READ;
@@ -1956,8 +2187,6 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
                        c->Request.CDB[0] = cmd;
                        break;
                case CCISS_READ_CAPACITY_16:
-                       c->Header.LUN.LogDev.VolId = h->drv[log_unit].LunID;
-                       c->Header.LUN.LogDev.Mode = 1;
                        c->Request.CDBLen = 16;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
                        c->Request.Type.Direction = XFER_READ;
@@ -1979,6 +2208,12 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
                        c->Request.CDB[0] = BMIC_WRITE;
                        c->Request.CDB[6] = BMIC_CACHE_FLUSH;
                        break;
+               case TEST_UNIT_READY:
+                       c->Request.CDBLen = 6;
+                       c->Request.Type.Attribute = ATTR_SIMPLE;
+                       c->Request.Type.Direction = XFER_NONE;
+                       c->Request.Timeout = 0;
+                       break;
                default:
                        printk(KERN_WARNING
                               "cciss%d:  Unknown Command 0x%c\n", ctlr, cmd);
@@ -1997,13 +2232,13 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
                        memcpy(&c->Request.CDB[4], buff, 8);
                        break;
                case 1: /* RESET message */
-                       c->Request.CDBLen = 12;
+                       c->Request.CDBLen = 16;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
-                       c->Request.Type.Direction = XFER_WRITE;
+                       c->Request.Type.Direction = XFER_NONE;
                        c->Request.Timeout = 0;
                        memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
                        c->Request.CDB[0] = cmd;        /* reset */
-                       c->Request.CDB[1] = 0x04;       /* reset a LUN */
+                       c->Request.CDB[1] = 0x03;       /* reset a target */
                        break;
                case 3: /* No-Op message */
                        c->Request.CDBLen = 1;
@@ -2035,114 +2270,152 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
        return status;
 }
 
-static int sendcmd_withirq(__u8 cmd,
-                          int ctlr,
-                          void *buff,
-                          size_t size,
-                          unsigned int use_unit_num,
-                          unsigned int log_unit, __u8 page_code, int cmd_type)
+static int check_target_status(ctlr_info_t *h, CommandList_struct *c)
 {
-       ctlr_info_t *h = hba[ctlr];
-       CommandList_struct *c;
+       switch (c->err_info->ScsiStatus) {
+       case SAM_STAT_GOOD:
+               return IO_OK;
+       case SAM_STAT_CHECK_CONDITION:
+               switch (0xf & c->err_info->SenseInfo[2]) {
+               case 0: return IO_OK; /* no sense */
+               case 1: return IO_OK; /* recovered error */
+               default:
+                       printk(KERN_WARNING "cciss%d: cmd 0x%02x "
+                               "check condition, sense key = 0x%02x\n",
+                               h->ctlr, c->Request.CDB[0],
+                               c->err_info->SenseInfo[2]);
+               }
+               break;
+       default:
+               printk(KERN_WARNING "cciss%d: cmd 0x%02x"
+                       "scsi status = 0x%02x\n", h->ctlr,
+                       c->Request.CDB[0], c->err_info->ScsiStatus);
+               break;
+       }
+       return IO_ERROR;
+}
+
+static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c)
+{
+       int return_status = IO_OK;
+
+       if (c->err_info->CommandStatus == CMD_SUCCESS)
+               return IO_OK;
+
+       switch (c->err_info->CommandStatus) {
+       case CMD_TARGET_STATUS:
+               return_status = check_target_status(h, c);
+               break;
+       case CMD_DATA_UNDERRUN:
+       case CMD_DATA_OVERRUN:
+               /* expected for inquiry and report lun commands */
+               break;
+       case CMD_INVALID:
+               printk(KERN_WARNING "cciss: cmd 0x%02x is "
+                      "reported invalid\n", c->Request.CDB[0]);
+               return_status = IO_ERROR;
+               break;
+       case CMD_PROTOCOL_ERR:
+               printk(KERN_WARNING "cciss: cmd 0x%02x has "
+                      "protocol error \n", c->Request.CDB[0]);
+               return_status = IO_ERROR;
+               break;
+       case CMD_HARDWARE_ERR:
+               printk(KERN_WARNING "cciss: cmd 0x%02x had "
+                      " hardware error\n", c->Request.CDB[0]);
+               return_status = IO_ERROR;
+               break;
+       case CMD_CONNECTION_LOST:
+               printk(KERN_WARNING "cciss: cmd 0x%02x had "
+                      "connection lost\n", c->Request.CDB[0]);
+               return_status = IO_ERROR;
+               break;
+       case CMD_ABORTED:
+               printk(KERN_WARNING "cciss: cmd 0x%02x was "
+                      "aborted\n", c->Request.CDB[0]);
+               return_status = IO_ERROR;
+               break;
+       case CMD_ABORT_FAILED:
+               printk(KERN_WARNING "cciss: cmd 0x%02x reports "
+                      "abort failed\n", c->Request.CDB[0]);
+               return_status = IO_ERROR;
+               break;
+       case CMD_UNSOLICITED_ABORT:
+               printk(KERN_WARNING
+                      "cciss%d: unsolicited abort 0x%02x\n", h->ctlr,
+                       c->Request.CDB[0]);
+               return_status = IO_NEEDS_RETRY;
+               break;
+       default:
+               printk(KERN_WARNING "cciss: cmd 0x%02x returned "
+                      "unknown status %x\n", c->Request.CDB[0],
+                      c->err_info->CommandStatus);
+               return_status = IO_ERROR;
+       }
+       return return_status;
+}
+
+static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c,
+       int attempt_retry)
+{
+       DECLARE_COMPLETION_ONSTACK(wait);
        u64bit buff_dma_handle;
        unsigned long flags;
-       int return_status;
-       DECLARE_COMPLETION_ONSTACK(wait);
+       int return_status = IO_OK;
 
-       if ((c = cmd_alloc(h, 0)) == NULL)
-               return -ENOMEM;
-       return_status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
-                                log_unit, page_code, NULL, cmd_type);
-       if (return_status != IO_OK) {
-               cmd_free(h, c, 0);
-               return return_status;
-       }
-      resend_cmd2:
+resend_cmd2:
        c->waiting = &wait;
-
        /* Put the request on the tail of the queue and send it */
-       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
        addQ(&h->reqQ, c);
        h->Qdepth++;
        start_io(h);
-       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
 
        wait_for_completion(&wait);
 
-       if (c->err_info->CommandStatus != 0) {  /* an error has occurred */
-               switch (c->err_info->CommandStatus) {
-               case CMD_TARGET_STATUS:
-                       printk(KERN_WARNING "cciss: cmd %p has "
-                              " completed with errors\n", c);
-                       if (c->err_info->ScsiStatus) {
-                               printk(KERN_WARNING "cciss: cmd %p "
-                                      "has SCSI Status = %x\n",
-                                      c, c->err_info->ScsiStatus);
-                       }
+       if (c->err_info->CommandStatus == 0 || !attempt_retry)
+               goto command_done;
 
-                       break;
-               case CMD_DATA_UNDERRUN:
-               case CMD_DATA_OVERRUN:
-                       /* expected for inquire and report lun commands */
-                       break;
-               case CMD_INVALID:
-                       printk(KERN_WARNING "cciss: Cmd %p is "
-                              "reported invalid\n", c);
-                       return_status = IO_ERROR;
-                       break;
-               case CMD_PROTOCOL_ERR:
-                       printk(KERN_WARNING "cciss: cmd %p has "
-                              "protocol error \n", c);
-                       return_status = IO_ERROR;
-                       break;
-               case CMD_HARDWARE_ERR:
-                       printk(KERN_WARNING "cciss: cmd %p had "
-                              " hardware error\n", c);
-                       return_status = IO_ERROR;
-                       break;
-               case CMD_CONNECTION_LOST:
-                       printk(KERN_WARNING "cciss: cmd %p had "
-                              "connection lost\n", c);
-                       return_status = IO_ERROR;
-                       break;
-               case CMD_ABORTED:
-                       printk(KERN_WARNING "cciss: cmd %p was "
-                              "aborted\n", c);
-                       return_status = IO_ERROR;
-                       break;
-               case CMD_ABORT_FAILED:
-                       printk(KERN_WARNING "cciss: cmd %p reports "
-                              "abort failed\n", c);
-                       return_status = IO_ERROR;
-                       break;
-               case CMD_UNSOLICITED_ABORT:
-                       printk(KERN_WARNING
-                              "cciss%d: unsolicited abort %p\n", ctlr, c);
-                       if (c->retry_count < MAX_CMD_RETRIES) {
-                               printk(KERN_WARNING
-                                      "cciss%d: retrying %p\n", ctlr, c);
-                               c->retry_count++;
-                               /* erase the old error information */
-                               memset(c->err_info, 0,
-                                      sizeof(ErrorInfo_struct));
-                               return_status = IO_OK;
-                               INIT_COMPLETION(wait);
-                               goto resend_cmd2;
-                       }
-                       return_status = IO_ERROR;
-                       break;
-               default:
-                       printk(KERN_WARNING "cciss: cmd %p returned "
-                              "unknown status %x\n", c,
-                              c->err_info->CommandStatus);
-                       return_status = IO_ERROR;
-               }
+       return_status = process_sendcmd_error(h, c);
+
+       if (return_status == IO_NEEDS_RETRY &&
+               c->retry_count < MAX_CMD_RETRIES) {
+               printk(KERN_WARNING "cciss%d: retrying 0x%02x\n", h->ctlr,
+                       c->Request.CDB[0]);
+               c->retry_count++;
+               /* erase the old error information */
+               memset(c->err_info, 0, sizeof(ErrorInfo_struct));
+               return_status = IO_OK;
+               INIT_COMPLETION(wait);
+               goto resend_cmd2;
        }
+
+command_done:
        /* unlock the buffers from DMA */
        buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
        buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
        pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val,
                         c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
+       return return_status;
+}
+
+static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
+                          __u8 page_code, unsigned char scsi3addr[],
+                       int cmd_type)
+{
+       ctlr_info_t *h = hba[ctlr];
+       CommandList_struct *c;
+       int return_status;
+
+       c = cmd_alloc(h, 0);
+       if (!c)
+               return -ENOMEM;
+       return_status = fill_cmd(c, cmd, ctlr, buff, size, page_code,
+               scsi3addr, cmd_type);
+       if (return_status == IO_OK)
+               return_status = sendcmd_withirq_core(h, c, 1);
+
        cmd_free(h, c, 0);
        return return_status;
 }
@@ -2155,15 +2428,17 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
 {
        int return_code;
        unsigned long t;
+       unsigned char scsi3addr[8];
 
        memset(inq_buff, 0, sizeof(InquiryData_struct));
+       log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
        if (withirq)
                return_code = sendcmd_withirq(CISS_INQUIRY, ctlr,
-                                             inq_buff, sizeof(*inq_buff), 1,
-                                             logvol, 0xC1, TYPE_CMD);
+                                             inq_buff, sizeof(*inq_buff),
+                                             0xC1, scsi3addr, TYPE_CMD);
        else
                return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff,
-                                     sizeof(*inq_buff), 1, logvol, 0xC1, NULL,
+                                     sizeof(*inq_buff), 0xC1, scsi3addr,
                                      TYPE_CMD);
        if (return_code == IO_OK) {
                if (inq_buff->data_byte[8] == 0xFF) {
@@ -2204,6 +2479,7 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
 {
        ReadCapdata_struct *buf;
        int return_code;
+       unsigned char scsi3addr[8];
 
        buf = kzalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
        if (!buf) {
@@ -2211,14 +2487,15 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
                return;
        }
 
+       log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
        if (withirq)
                return_code = sendcmd_withirq(CCISS_READ_CAPACITY,
                                ctlr, buf, sizeof(ReadCapdata_struct),
-                                       1, logvol, 0, TYPE_CMD);
+                                       0, scsi3addr, TYPE_CMD);
        else
                return_code = sendcmd(CCISS_READ_CAPACITY,
                                ctlr, buf, sizeof(ReadCapdata_struct),
-                                       1, logvol, 0, NULL, TYPE_CMD);
+                                       0, scsi3addr, TYPE_CMD);
        if (return_code == IO_OK) {
                *total_size = be32_to_cpu(*(__be32 *) buf->total_size);
                *block_size = be32_to_cpu(*(__be32 *) buf->block_size);
@@ -2238,6 +2515,7 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size,
 {
        ReadCapdata_struct_16 *buf;
        int return_code;
+       unsigned char scsi3addr[8];
 
        buf = kzalloc(sizeof(ReadCapdata_struct_16), GFP_KERNEL);
        if (!buf) {
@@ -2245,15 +2523,16 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size,
                return;
        }
 
+       log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
        if (withirq) {
                return_code = sendcmd_withirq(CCISS_READ_CAPACITY_16,
                        ctlr, buf, sizeof(ReadCapdata_struct_16),
-                               1, logvol, 0, TYPE_CMD);
+                               0, scsi3addr, TYPE_CMD);
        }
        else {
                return_code = sendcmd(CCISS_READ_CAPACITY_16,
                        ctlr, buf, sizeof(ReadCapdata_struct_16),
-                               1, logvol, 0, NULL, TYPE_CMD);
+                               0, scsi3addr, TYPE_CMD);
        }
        if (return_code == IO_OK) {
                *total_size = be64_to_cpu(*(__be64 *) buf->total_size);
@@ -2303,7 +2582,7 @@ static int cciss_revalidate(struct gendisk *disk)
        cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size,
                               inq_buff, drv);
 
-       blk_queue_hardsect_size(drv->queue, drv->block_size);
+       blk_queue_logical_block_size(drv->queue, drv->block_size);
        set_capacity(disk, drv->nr_blocks);
 
        kfree(inq_buff);
@@ -2333,86 +2612,21 @@ static unsigned long pollcomplete(int ctlr)
        return 1;
 }
 
-static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
-{
-       /* We get in here if sendcmd() is polling for completions
-          and gets some command back that it wasn't expecting --
-          something other than that which it just sent down.
-          Ordinarily, that shouldn't happen, but it can happen when
-          the scsi tape stuff gets into error handling mode, and
-          starts using sendcmd() to try to abort commands and
-          reset tape drives.  In that case, sendcmd may pick up
-          completions of commands that were sent to logical drives
-          through the block i/o system, or cciss ioctls completing, etc.
-          In that case, we need to save those completions for later
-          processing by the interrupt handler.
-        */
-
-#ifdef CONFIG_CISS_SCSI_TAPE
-       struct sendcmd_reject_list *srl = &hba[ctlr]->scsi_rejects;
-
-       /* If it's not the scsi tape stuff doing error handling, (abort */
-       /* or reset) then we don't expect anything weird. */
-       if (cmd != CCISS_RESET_MSG && cmd != CCISS_ABORT_MSG) {
-#endif
-               printk(KERN_WARNING "cciss cciss%d: SendCmd "
-                      "Invalid command list address returned! (%lx)\n",
-                      ctlr, complete);
-               /* not much we can do. */
-#ifdef CONFIG_CISS_SCSI_TAPE
-               return 1;
-       }
-
-       /* We've sent down an abort or reset, but something else
-          has completed */
-       if (srl->ncompletions >= (hba[ctlr]->nr_cmds + 2)) {
-               /* Uh oh.  No room to save it for later... */
-               printk(KERN_WARNING "cciss%d: Sendcmd: Invalid command addr, "
-                      "reject list overflow, command lost!\n", ctlr);
-               return 1;
-       }
-       /* Save it for later */
-       srl->complete[srl->ncompletions] = complete;
-       srl->ncompletions++;
-#endif
-       return 0;
-}
-
-/*
- * Send a command to the controller, and wait for it to complete.
- * Only used at init time.
+/* Send command c to controller h and poll for it to complete.
+ * Turns interrupts off on the board.  Used at driver init time
+ * and during SCSI error recovery.
  */
-static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num,     /* 0: address the controller,
-                                                                                                  1: address logical volume log_unit,
-                                                                                                  2: periph device address is scsi3addr */
-                  unsigned int log_unit,
-                  __u8 page_code, unsigned char *scsi3addr, int cmd_type)
+static int sendcmd_core(ctlr_info_t *h, CommandList_struct *c)
 {
-       CommandList_struct *c;
        int i;
        unsigned long complete;
-       ctlr_info_t *info_p = hba[ctlr];
+       int status = IO_ERROR;
        u64bit buff_dma_handle;
-       int status, done = 0;
 
-       if ((c = cmd_alloc(info_p, 1)) == NULL) {
-               printk(KERN_WARNING "cciss: unable to get memory");
-               return IO_ERROR;
-       }
-       status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
-                         log_unit, page_code, scsi3addr, cmd_type);
-       if (status != IO_OK) {
-               cmd_free(info_p, c, 1);
-               return status;
-       }
-      resend_cmd1:
-       /*
-        * Disable interrupt
-        */
-#ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "cciss: turning intr off\n");
-#endif                         /* CCISS_DEBUG */
-       info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF);
+resend_cmd1:
+
+       /* Disable interrupt on the board. */
+       h->access.set_intr_mask(h, CCISS_INTR_OFF);
 
        /* Make sure there is room in the command FIFO */
        /* Actually it should be completely empty at this time */
@@ -2420,21 +2634,15 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use
        /* tape side of the driver. */
        for (i = 200000; i > 0; i--) {
                /* if fifo isn't full go */
-               if (!(info_p->access.fifo_full(info_p))) {
-
+               if (!(h->access.fifo_full(h)))
                        break;
-               }
                udelay(10);
                printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
-                      " waiting!\n", ctlr);
+                      " waiting!\n", h->ctlr);
        }
-       /*
-        * Send the cmd
-        */
-       info_p->access.submit_command(info_p, c);
-       done = 0;
+       h->access.submit_command(h, c); /* Send the cmd */
        do {
-               complete = pollcomplete(ctlr);
+               complete = pollcomplete(h->ctlr);
 
 #ifdef CCISS_DEBUG
                printk(KERN_DEBUG "cciss: command completed\n");
@@ -2443,97 +2651,102 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use
                if (complete == 1) {
                        printk(KERN_WARNING
                               "cciss cciss%d: SendCmd Timeout out, "
-                              "No command list address returned!\n", ctlr);
+                              "No command list address returned!\n", h->ctlr);
                        status = IO_ERROR;
-                       done = 1;
                        break;
                }
 
-               /* This will need to change for direct lookup completions */
-               if ((complete & CISS_ERROR_BIT)
-                   && (complete & ~CISS_ERROR_BIT) == c->busaddr) {
-                       /* if data overrun or underun on Report command
-                          ignore it
-                        */
-                       if (((c->Request.CDB[0] == CISS_REPORT_LOG) ||
-                            (c->Request.CDB[0] == CISS_REPORT_PHYS) ||
-                            (c->Request.CDB[0] == CISS_INQUIRY)) &&
-                           ((c->err_info->CommandStatus ==
-                             CMD_DATA_OVERRUN) ||
-                            (c->err_info->CommandStatus == CMD_DATA_UNDERRUN)
-                           )) {
-                               complete = c->busaddr;
-                       } else {
-                               if (c->err_info->CommandStatus ==
-                                   CMD_UNSOLICITED_ABORT) {
-                                       printk(KERN_WARNING "cciss%d: "
-                                              "unsolicited abort %p\n",
-                                              ctlr, c);
-                                       if (c->retry_count < MAX_CMD_RETRIES) {
-                                               printk(KERN_WARNING
-                                                      "cciss%d: retrying %p\n",
-                                                      ctlr, c);
-                                               c->retry_count++;
-                                               /* erase the old error */
-                                               /* information */
-                                               memset(c->err_info, 0,
-                                                      sizeof
-                                                      (ErrorInfo_struct));
-                                               goto resend_cmd1;
-                                       } else {
-                                               printk(KERN_WARNING
-                                                      "cciss%d: retried %p too "
-                                                      "many times\n", ctlr, c);
-                                               status = IO_ERROR;
-                                               goto cleanup1;
-                                       }
-                               } else if (c->err_info->CommandStatus ==
-                                          CMD_UNABORTABLE) {
-                                       printk(KERN_WARNING
-                                              "cciss%d: command could not be aborted.\n",
-                                              ctlr);
-                                       status = IO_ERROR;
-                                       goto cleanup1;
-                               }
-                               printk(KERN_WARNING "ciss ciss%d: sendcmd"
-                                      " Error %x \n", ctlr,
-                                      c->err_info->CommandStatus);
-                               printk(KERN_WARNING "ciss ciss%d: sendcmd"
-                                      " offensive info\n"
-                                      "  size %x\n   num %x   value %x\n",
-                                      ctlr,
-                                      c->err_info->MoreErrInfo.Invalid_Cmd.
-                                      offense_size,
-                                      c->err_info->MoreErrInfo.Invalid_Cmd.
-                                      offense_num,
-                                      c->err_info->MoreErrInfo.Invalid_Cmd.
-                                      offense_value);
-                               status = IO_ERROR;
-                               goto cleanup1;
-                       }
+               /* Make sure it's the command we're expecting. */
+               if ((complete & ~CISS_ERROR_BIT) != c->busaddr) {
+                       printk(KERN_WARNING "cciss%d: Unexpected command "
+                               "completion.\n", h->ctlr);
+                       continue;
+               }
+
+               /* It is our command.  If no error, we're done. */
+               if (!(complete & CISS_ERROR_BIT)) {
+                       status = IO_OK;
+                       break;
                }
-               /* This will need changing for direct lookup completions */
-               if (complete != c->busaddr) {
-                       if (add_sendcmd_reject(cmd, ctlr, complete) != 0) {
-                               BUG();  /* we are pretty much hosed if we get here. */
+
+               /* There is an error... */
+
+               /* if data overrun or underun on Report command ignore it */
+               if (((c->Request.CDB[0] == CISS_REPORT_LOG) ||
+                    (c->Request.CDB[0] == CISS_REPORT_PHYS) ||
+                    (c->Request.CDB[0] == CISS_INQUIRY)) &&
+                       ((c->err_info->CommandStatus == CMD_DATA_OVERRUN) ||
+                        (c->err_info->CommandStatus == CMD_DATA_UNDERRUN))) {
+                       complete = c->busaddr;
+                       status = IO_OK;
+                       break;
+               }
+
+               if (c->err_info->CommandStatus == CMD_UNSOLICITED_ABORT) {
+                       printk(KERN_WARNING "cciss%d: unsolicited abort %p\n",
+                               h->ctlr, c);
+                       if (c->retry_count < MAX_CMD_RETRIES) {
+                               printk(KERN_WARNING "cciss%d: retrying %p\n",
+                                  h->ctlr, c);
+                               c->retry_count++;
+                               /* erase the old error information */
+                               memset(c->err_info, 0, sizeof(c->err_info));
+                               goto resend_cmd1;
                        }
-                       continue;
-               } else
-                       done = 1;
-       } while (!done);
+                       printk(KERN_WARNING "cciss%d: retried %p too many "
+                               "times\n", h->ctlr, c);
+                       status = IO_ERROR;
+                       break;
+               }
+
+               if (c->err_info->CommandStatus == CMD_UNABORTABLE) {
+                       printk(KERN_WARNING "cciss%d: command could not be "
+                               "aborted.\n", h->ctlr);
+                       status = IO_ERROR;
+                       break;
+               }
+
+               if (c->err_info->CommandStatus == CMD_TARGET_STATUS) {
+                       status = check_target_status(h, c);
+                       break;
+               }
+
+               printk(KERN_WARNING "cciss%d: sendcmd error\n", h->ctlr);
+               printk(KERN_WARNING "cmd = 0x%02x, CommandStatus = 0x%02x\n",
+                       c->Request.CDB[0], c->err_info->CommandStatus);
+               status = IO_ERROR;
+               break;
+
+       } while (1);
 
-      cleanup1:
        /* unlock the data buffer from DMA */
        buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
        buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
-       pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
+       pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val,
                         c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
-#ifdef CONFIG_CISS_SCSI_TAPE
-       /* if we saved some commands for later, process them now. */
-       if (info_p->scsi_rejects.ncompletions > 0)
-               do_cciss_intr(0, info_p);
-#endif
-       cmd_free(info_p, c, 1);
+       return status;
+}
+
+/*
+ * Send a command to the controller, and wait for it to complete.
+ * Used at init time, and during SCSI error recovery.
+ */
+static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size,
+       __u8 page_code, unsigned char *scsi3addr, int cmd_type)
+{
+       CommandList_struct *c;
+       int status;
+
+       c = cmd_alloc(hba[ctlr], 1);
+       if (!c) {
+               printk(KERN_WARNING "cciss: unable to get memory");
+               return IO_ERROR;
+       }
+       status = fill_cmd(c, cmd, ctlr, buff, size, page_code,
+               scsi3addr, cmd_type);
+       if (status == IO_OK)
+               status = sendcmd_core(hba[ctlr], c);
+       cmd_free(hba[ctlr], c, 1);
        return status;
 }
 
@@ -2691,7 +2904,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
                        printk(KERN_WARNING "cciss: cmd %p has"
                               " completed with data underrun "
                               "reported\n", cmd);
-                       cmd->rq->data_len = cmd->err_info->ResidualCnt;
+                       cmd->rq->resid_len = cmd->err_info->ResidualCnt;
                }
                break;
        case CMD_DATA_OVERRUN:
@@ -2806,7 +3019,7 @@ static void do_cciss_request(struct request_queue *q)
                goto startio;
 
       queue:
-       creq = elv_next_request(q);
+       creq = blk_peek_request(q);
        if (!creq)
                goto startio;
 
@@ -2815,7 +3028,7 @@ static void do_cciss_request(struct request_queue *q)
        if ((c = cmd_alloc(h, 1)) == NULL)
                goto full;
 
-       blkdev_dequeue_request(creq);
+       blk_start_request(creq);
 
        spin_unlock_irq(q->queue_lock);
 
@@ -2840,10 +3053,10 @@ static void do_cciss_request(struct request_queue *q)
        c->Request.Timeout = 0; // Don't time out
        c->Request.CDB[0] =
            (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write;
-       start_blk = creq->sector;
+       start_blk = blk_rq_pos(creq);
 #ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n", (int)creq->sector,
-              (int)creq->nr_sectors);
+       printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",
+              (int)blk_rq_pos(creq), (int)blk_rq_sectors(creq));
 #endif                         /* CCISS_DEBUG */
 
        sg_init_table(tmp_sg, MAXSGENTRIES);
@@ -2869,8 +3082,8 @@ static void do_cciss_request(struct request_queue *q)
                h->maxSG = seg;
 
 #ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "cciss: Submitting %lu sectors in %d segments\n",
-              creq->nr_sectors, seg);
+       printk(KERN_DEBUG "cciss: Submitting %u sectors in %d segments\n",
+              blk_rq_sectors(creq), seg);
 #endif                         /* CCISS_DEBUG */
 
        c->Header.SGList = c->Header.SGTotal = seg;
@@ -2882,8 +3095,8 @@ static void do_cciss_request(struct request_queue *q)
                        c->Request.CDB[4] = (start_blk >> 8) & 0xff;
                        c->Request.CDB[5] = start_blk & 0xff;
                        c->Request.CDB[6] = 0;  // (sect >> 24) & 0xff; MSB
-                       c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
-                       c->Request.CDB[8] = creq->nr_sectors & 0xff;
+                       c->Request.CDB[7] = (blk_rq_sectors(creq) >> 8) & 0xff;
+                       c->Request.CDB[8] = blk_rq_sectors(creq) & 0xff;
                        c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
                } else {
                        u32 upper32 = upper_32_bits(start_blk);
@@ -2898,10 +3111,10 @@ static void do_cciss_request(struct request_queue *q)
                        c->Request.CDB[7]= (start_blk >> 16) & 0xff;
                        c->Request.CDB[8]= (start_blk >>  8) & 0xff;
                        c->Request.CDB[9]= start_blk & 0xff;
-                       c->Request.CDB[10]= (creq->nr_sectors >>  24) & 0xff;
-                       c->Request.CDB[11]= (creq->nr_sectors >>  16) & 0xff;
-                       c->Request.CDB[12]= (creq->nr_sectors >>  8) & 0xff;
-                       c->Request.CDB[13]= creq->nr_sectors & 0xff;
+                       c->Request.CDB[10]= (blk_rq_sectors(creq) >> 24) & 0xff;
+                       c->Request.CDB[11]= (blk_rq_sectors(creq) >> 16) & 0xff;
+                       c->Request.CDB[12]= (blk_rq_sectors(creq) >>  8) & 0xff;
+                       c->Request.CDB[13]= blk_rq_sectors(creq) & 0xff;
                        c->Request.CDB[14] = c->Request.CDB[15] = 0;
                }
        } else if (blk_pc_request(creq)) {
@@ -2931,44 +3144,18 @@ startio:
 
 static inline unsigned long get_next_completion(ctlr_info_t *h)
 {
-#ifdef CONFIG_CISS_SCSI_TAPE
-       /* Any rejects from sendcmd() lying around? Process them first */
-       if (h->scsi_rejects.ncompletions == 0)
-               return h->access.command_completed(h);
-       else {
-               struct sendcmd_reject_list *srl;
-               int n;
-               srl = &h->scsi_rejects;
-               n = --srl->ncompletions;
-               /* printk("cciss%d: processing saved reject\n", h->ctlr); */
-               printk("p");
-               return srl->complete[n];
-       }
-#else
        return h->access.command_completed(h);
-#endif
 }
 
 static inline int interrupt_pending(ctlr_info_t *h)
 {
-#ifdef CONFIG_CISS_SCSI_TAPE
-       return (h->access.intr_pending(h)
-               || (h->scsi_rejects.ncompletions > 0));
-#else
        return h->access.intr_pending(h);
-#endif
 }
 
 static inline long interrupt_not_for_us(ctlr_info_t *h)
 {
-#ifdef CONFIG_CISS_SCSI_TAPE
-       return (((h->access.intr_pending(h) == 0) ||
-                (h->interrupts_enabled == 0))
-               && (h->scsi_rejects.ncompletions == 0));
-#else
        return (((h->access.intr_pending(h) == 0) ||
                 (h->interrupts_enabled == 0)));
-#endif
 }
 
 static irqreturn_t do_cciss_intr(int irq, void *dev_id)
@@ -3723,12 +3910,15 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        INIT_HLIST_HEAD(&hba[i]->reqQ);
 
        if (cciss_pci_init(hba[i], pdev) != 0)
-               goto clean1;
+               goto clean0;
 
        sprintf(hba[i]->devname, "cciss%d", i);
        hba[i]->ctlr = i;
        hba[i]->pdev = pdev;
 
+       if (cciss_create_hba_sysfs_entry(hba[i]))
+               goto clean0;
+
        /* configure PCI DMA stuff */
        if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
                dac = 1;
@@ -3787,15 +3977,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                printk(KERN_ERR "cciss: out of memory");
                goto clean4;
        }
-#ifdef CONFIG_CISS_SCSI_TAPE
-       hba[i]->scsi_rejects.complete =
-           kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) *
-                   (hba[i]->nr_cmds + 5), GFP_KERNEL);
-       if (hba[i]->scsi_rejects.complete == NULL) {
-               printk(KERN_ERR "cciss: out of memory");
-               goto clean4;
-       }
-#endif
        spin_lock_init(&hba[i]->lock);
 
        /* Initialize the pdev driver private data.
@@ -3828,7 +4009,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        }
 
        return_code = sendcmd_withirq(CISS_INQUIRY, i, inq_buff,
-               sizeof(InquiryData_struct), 0, 0 , 0, TYPE_CMD);
+               sizeof(InquiryData_struct), 0, CTLR_LUNID, TYPE_CMD);
        if (return_code == IO_OK) {
                hba[i]->firm_ver[0] = inq_buff->data_byte[32];
                hba[i]->firm_ver[1] = inq_buff->data_byte[33];
@@ -3855,9 +4036,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 
 clean4:
        kfree(inq_buff);
-#ifdef CONFIG_CISS_SCSI_TAPE
-       kfree(hba[i]->scsi_rejects.complete);
-#endif
        kfree(hba[i]->cmd_pool_bits);
        if (hba[i]->cmd_pool)
                pci_free_consistent(hba[i]->pdev,
@@ -3872,6 +4050,8 @@ clean4:
 clean2:
        unregister_blkdev(hba[i]->major, hba[i]->devname);
 clean1:
+       cciss_destroy_hba_sysfs_entry(hba[i]);
+clean0:
        hba[i]->busy_initializing = 0;
        /* cleanup any queues that may have been initialized */
        for (j=0; j <= hba[i]->highest_lun; j++){
@@ -3907,8 +4087,8 @@ static void cciss_shutdown(struct pci_dev *pdev)
        /* sendcmd will turn off interrupt, and send the flush...
         * To write all data in the battery backed cache to disks */
        memset(flush_buf, 0, 4);
-       return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL,
-                             TYPE_CMD);
+       return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0,
+               CTLR_LUNID, TYPE_CMD);
        if (return_code == IO_OK) {
                printk(KERN_INFO "Completed flushing cache on controller %d\n", i);
        } else {
@@ -3973,15 +4153,13 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
        pci_free_consistent(hba[i]->pdev, hba[i]->nr_cmds * sizeof(ErrorInfo_struct),
                            hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
        kfree(hba[i]->cmd_pool_bits);
-#ifdef CONFIG_CISS_SCSI_TAPE
-       kfree(hba[i]->scsi_rejects.complete);
-#endif
        /*
         * Deliberately omit pci_disable_device(): it does something nasty to
         * Smart Array controllers that pci_enable_device does not undo
         */
        pci_release_regions(pdev);
        pci_set_drvdata(pdev, NULL);
+       cciss_destroy_hba_sysfs_entry(hba[i]);
        free_hba(i);
 }
 
@@ -3999,6 +4177,8 @@ static struct pci_driver cciss_pci_driver = {
  */
 static int __init cciss_init(void)
 {
+       int err;
+
        /*
         * The hardware requires that commands are aligned on a 64-bit
         * boundary. Given that we use pci_alloc_consistent() to allocate an
@@ -4008,8 +4188,20 @@ static int __init cciss_init(void)
 
        printk(KERN_INFO DRIVER_NAME "\n");
 
+       err = bus_register(&cciss_bus_type);
+       if (err)
+               return err;
+
        /* Register for our PCI devices */
-       return pci_register_driver(&cciss_pci_driver);
+       err = pci_register_driver(&cciss_pci_driver);
+       if (err)
+               goto err_bus_register;
+
+       return 0;
+
+err_bus_register:
+       bus_unregister(&cciss_bus_type);
+       return err;
 }
 
 static void __exit cciss_cleanup(void)
@@ -4026,6 +4218,7 @@ static void __exit cciss_cleanup(void)
                }
        }
        remove_proc_entry("driver/cciss", NULL);
+       bus_unregister(&cciss_bus_type);
 }
 
 static void fail_all_cmds(unsigned long ctlr)
index 703e08038fb936ec722e23fafcf65a33cf411896..06a5db25b298ebf400c99ac1c8fa200e208d10ae 100644 (file)
 
 #define IO_OK          0
 #define IO_ERROR       1
+#define IO_NEEDS_RETRY  3
+
+#define VENDOR_LEN     8
+#define MODEL_LEN      16
+#define REV_LEN                4
 
 struct ctlr_info;
 typedef struct ctlr_info ctlr_info_t;
@@ -34,23 +39,20 @@ typedef struct _drive_info_struct
        int     cylinders;
        int     raid_level; /* set to -1 to indicate that
                             * the drive is not in use/configured
-                           */
-       int     busy_configuring; /*This is set when the drive is being removed
-                                  *to prevent it from being opened or it's queue
-                                  *from being started.
-                                 */
-       __u8 serial_no[16]; /* from inquiry page 0x83, */
-                           /* not necc. null terminated. */
+                            */
+       int     busy_configuring; /* This is set when a drive is being removed
+                                  * to prevent it from being opened or it's
+                                  * queue from being started.
+                                  */
+       struct  device dev;
+       __u8 serial_no[16]; /* from inquiry page 0x83,
+                            * not necc. null terminated.
+                            */
+       char vendor[VENDOR_LEN + 1]; /* SCSI vendor string */
+       char model[MODEL_LEN + 1];   /* SCSI model string */
+       char rev[REV_LEN + 1];       /* SCSI revision string */
 } drive_info_struct;
 
-#ifdef CONFIG_CISS_SCSI_TAPE
-
-struct sendcmd_reject_list {
-       int ncompletions;
-       unsigned long *complete; /* array of NR_CMDS tags */
-};
-
-#endif
 struct ctlr_info 
 {
        int     ctlr;
@@ -118,11 +120,11 @@ struct ctlr_info
        void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
        /* list of block side commands the scsi error handling sucked up */
        /* and saved for later processing */
-       struct sendcmd_reject_list scsi_rejects;
 #endif
        unsigned char alive;
        struct completion *rescan_wait;
        struct task_struct *cciss_scan_thread;
+       struct device dev;
 };
 
 /*  Defining the diffent access_menthods */
index 40b1b92dae7fcdd5a212d45f5706a194181c3442..cd665b00c7c5b333176e160102fc25f5b6f998e5 100644 (file)
@@ -217,6 +217,8 @@ typedef union _LUNAddr_struct {
   LogDevAddr_struct  LogDev;
 } LUNAddr_struct;
 
+#define CTLR_LUNID "\0\0\0\0\0\0\0\0"
+
 typedef struct _CommandListHeader_struct {
   BYTE              ReplyQueue;
   BYTE              SGList;
index a3fd87b414444a7f094643a6047f25c1f0118a13..3315268b4ec7debaa9733b725aa0de63100e29c6 100644 (file)
 #define CCISS_ABORT_MSG 0x00
 #define CCISS_RESET_MSG 0x01
 
-/* some prototypes... */ 
-static int sendcmd(
-       __u8    cmd,
-       int     ctlr,
-       void    *buff,
-       size_t  size,
-       unsigned int use_unit_num, /* 0: address the controller,
-                                     1: address logical volume log_unit, 
-                                     2: address is in scsi3addr */
-       unsigned int log_unit,
-       __u8    page_code,
-       unsigned char *scsi3addr,
+static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
+       size_t size,
+       __u8 page_code, unsigned char *scsi3addr,
        int cmd_type);
 
+static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool);
+static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool);
 
 static int cciss_scsi_proc_info(
                struct Scsi_Host *sh,
@@ -1575,6 +1568,75 @@ cciss_seq_tape_report(struct seq_file *seq, int ctlr)
        CPQ_TAPE_UNLOCK(ctlr, flags);
 }
 
+static int wait_for_device_to_become_ready(ctlr_info_t *h,
+       unsigned char lunaddr[])
+{
+       int rc;
+       int count = 0;
+       int waittime = HZ;
+       CommandList_struct *c;
+
+       c = cmd_alloc(h, 1);
+       if (!c) {
+               printk(KERN_WARNING "cciss%d: out of memory in "
+                       "wait_for_device_to_become_ready.\n", h->ctlr);
+               return IO_ERROR;
+       }
+
+       /* Send test unit ready until device ready, or give up. */
+       while (count < 20) {
+
+               /* Wait for a bit.  do this first, because if we send
+                * the TUR right away, the reset will just abort it.
+                */
+               schedule_timeout_uninterruptible(waittime);
+               count++;
+
+               /* Increase wait time with each try, up to a point. */
+               if (waittime < (HZ * 30))
+                       waittime = waittime * 2;
+
+               /* Send the Test Unit Ready */
+               rc = fill_cmd(c, TEST_UNIT_READY, h->ctlr, NULL, 0, 0,
+                       lunaddr, TYPE_CMD);
+               if (rc == 0)
+                       rc = sendcmd_withirq_core(h, c, 0);
+
+               (void) process_sendcmd_error(h, c);
+
+               if (rc != 0)
+                       goto retry_tur;
+
+               if (c->err_info->CommandStatus == CMD_SUCCESS)
+                       break;
+
+               if (c->err_info->CommandStatus == CMD_TARGET_STATUS &&
+                       c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION) {
+                       if (c->err_info->SenseInfo[2] == NO_SENSE)
+                               break;
+                       if (c->err_info->SenseInfo[2] == UNIT_ATTENTION) {
+                               unsigned char asc;
+                               asc = c->err_info->SenseInfo[12];
+                               check_for_unit_attention(h, c);
+                               if (asc == POWER_OR_RESET)
+                                       break;
+                       }
+               }
+retry_tur:
+               printk(KERN_WARNING "cciss%d: Waiting %d secs "
+                       "for device to become ready.\n",
+                       h->ctlr, waittime / HZ);
+               rc = 1; /* device not ready. */
+       }
+
+       if (rc)
+               printk("cciss%d: giving up on device.\n", h->ctlr);
+       else
+               printk(KERN_WARNING "cciss%d: device is ready.\n", h->ctlr);
+
+       cmd_free(h, c, 1);
+       return rc;
+}
 
 /* Need at least one of these error handlers to keep ../scsi/hosts.c from 
  * complaining.  Doing a host- or bus-reset can't do anything good here. 
@@ -1591,6 +1653,7 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
 {
        int rc;
        CommandList_struct *cmd_in_trouble;
+       unsigned char lunaddr[8];
        ctlr_info_t **c;
        int ctlr;
 
@@ -1600,19 +1663,15 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
                return FAILED;
        ctlr = (*c)->ctlr;
        printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr);
-
        /* find the command that's giving us trouble */
        cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble;
-       if (cmd_in_trouble == NULL) /* paranoia */
+       if (cmd_in_trouble == NULL) /* paranoia */
                return FAILED;
-       }
+       memcpy(lunaddr, &cmd_in_trouble->Header.LUN.LunAddrBytes[0], 8);
        /* send a reset to the SCSI LUN which the command was sent to */
-       rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0, 
-               (unsigned char *) &cmd_in_trouble->Header.LUN.LunAddrBytes[0], 
+       rc = sendcmd_withirq(CCISS_RESET_MSG, ctlr, NULL, 0, 0, lunaddr,
                TYPE_MSG);
-       /* sendcmd turned off interrupts on the board, turn 'em back on. */
-       (*c)->access.set_intr_mask(*c, CCISS_INTR_ON);
-       if (rc == 0)
+       if (rc == 0 && wait_for_device_to_become_ready(*c, lunaddr) == 0)
                return SUCCESS;
        printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr);
        return FAILED;
@@ -1622,6 +1681,7 @@ static int  cciss_eh_abort_handler(struct scsi_cmnd *scsicmd)
 {
        int rc;
        CommandList_struct *cmd_to_abort;
+       unsigned char lunaddr[8];
        ctlr_info_t **c;
        int ctlr;
 
@@ -1636,12 +1696,9 @@ static int  cciss_eh_abort_handler(struct scsi_cmnd *scsicmd)
        cmd_to_abort = (CommandList_struct *) scsicmd->host_scribble;
        if (cmd_to_abort == NULL) /* paranoia */
                return FAILED;
-       rc = sendcmd(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag, 
-               0, 2, 0, 0, 
-               (unsigned char *) &cmd_to_abort->Header.LUN.LunAddrBytes[0], 
-               TYPE_MSG);
-       /* sendcmd turned off interrupts on the board, turn 'em back on. */
-       (*c)->access.set_intr_mask(*c, CCISS_INTR_ON);
+       memcpy(lunaddr, &cmd_to_abort->Header.LUN.LunAddrBytes[0], 8);
+       rc = sendcmd_withirq(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag,
+               0, 0, lunaddr, TYPE_MSG);
        if (rc == 0)
                return SUCCESS;
        return FAILED;
index ca268ca111598588ef52d9f7ca7e0fa87cfbde86..44fa2018f6b027b8b5bb77504bef118a813168e3 100644 (file)
@@ -474,7 +474,7 @@ static int __init cpqarray_register_ctlr( int i, struct pci_dev *pdev)
                disk->fops = &ida_fops;
                if (j && !drv->nr_blks)
                        continue;
-               blk_queue_hardsect_size(hba[i]->queue, drv->blk_size);
+               blk_queue_logical_block_size(hba[i]->queue, drv->blk_size);
                set_capacity(disk, drv->nr_blks);
                disk->queue = hba[i]->queue;
                disk->private_data = drv;
@@ -903,7 +903,7 @@ static void do_ida_request(struct request_queue *q)
                goto startio;
 
 queue_next:
-       creq = elv_next_request(q);
+       creq = blk_peek_request(q);
        if (!creq)
                goto startio;
 
@@ -912,17 +912,18 @@ queue_next:
        if ((c = cmd_alloc(h,1)) == NULL)
                goto startio;
 
-       blkdev_dequeue_request(creq);
+       blk_start_request(creq);
 
        c->ctlr = h->ctlr;
        c->hdr.unit = (drv_info_t *)(creq->rq_disk->private_data) - h->drv;
        c->hdr.size = sizeof(rblk_t) >> 2;
        c->size += sizeof(rblk_t);
 
-       c->req.hdr.blk = creq->sector;
+       c->req.hdr.blk = blk_rq_pos(creq);
        c->rq = creq;
 DBGPX(
-       printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors);
+       printk("sector=%d, nr_sectors=%u\n",
+              blk_rq_pos(creq), blk_rq_sectors(creq));
 );
        sg_init_table(tmp_sg, SG_MAX);
        seg = blk_rq_map_sg(q, creq, tmp_sg);
@@ -940,9 +941,9 @@ DBGPX(
                                                 tmp_sg[i].offset,
                                                 tmp_sg[i].length, dir);
        }
-DBGPX( printk("Submitting %d sectors in %d segments\n", creq->nr_sectors, seg); );
+DBGPX( printk("Submitting %u sectors in %d segments\n", blk_rq_sectors(creq), seg); );
        c->req.hdr.sg_cnt = seg;
-       c->req.hdr.blk_cnt = creq->nr_sectors;
+       c->req.hdr.blk_cnt = blk_rq_sectors(creq);
        c->req.hdr.cmd = (rq_data_dir(creq) == READ) ? IDA_READ : IDA_WRITE;
        c->type = CMD_RWREQ;
 
@@ -1024,8 +1025,7 @@ static inline void complete_command(cmdlist_t *cmd, int timeout)
                                cmd->req.sg[i].size, ddir);
 
        DBGPX(printk("Done with %p\n", rq););
-       if (__blk_end_request(rq, error, blk_rq_bytes(rq)))
-               BUG();
+       __blk_end_request_all(rq, error);
 }
 
 /*
@@ -1546,7 +1546,7 @@ static int revalidate_allvol(ctlr_info_t *host)
                drv_info_t *drv = &host->drv[i];
                if (i && !drv->nr_blks)
                        continue;
-               blk_queue_hardsect_size(host->queue, drv->blk_size);
+               blk_queue_logical_block_size(host->queue, drv->blk_size);
                set_capacity(disk, drv->nr_blks);
                disk->queue = host->queue;
                disk->private_data = drv;
index 1300df6f1642a9a84fb345c22f9f88850cd1fe29..862b40c90181b008f91f22aef61e69e87c681123 100644 (file)
@@ -931,7 +931,7 @@ static inline void unlock_fdc(void)
        del_timer(&fd_timeout);
        cont = NULL;
        clear_bit(0, &fdc_busy);
-       if (elv_next_request(floppy_queue))
+       if (current_req || blk_peek_request(floppy_queue))
                do_fd_request(floppy_queue);
        spin_unlock_irqrestore(&floppy_lock, flags);
        wake_up(&fdc_wait);
@@ -2303,7 +2303,7 @@ static void floppy_end_request(struct request *req, int error)
 
        /* current_count_sectors can be zero if transfer failed */
        if (error)
-               nr_sectors = req->current_nr_sectors;
+               nr_sectors = blk_rq_cur_sectors(req);
        if (__blk_end_request(req, error, nr_sectors << 9))
                return;
 
@@ -2332,7 +2332,7 @@ static void request_done(int uptodate)
        if (uptodate) {
                /* maintain values for invalidation on geometry
                 * change */
-               block = current_count_sectors + req->sector;
+               block = current_count_sectors + blk_rq_pos(req);
                INFBOUND(DRS->maxblock, block);
                if (block > _floppy->sect)
                        DRS->maxtrack = 1;
@@ -2346,10 +2346,10 @@ static void request_done(int uptodate)
                        /* record write error information */
                        DRWE->write_errors++;
                        if (DRWE->write_errors == 1) {
-                               DRWE->first_error_sector = req->sector;
+                               DRWE->first_error_sector = blk_rq_pos(req);
                                DRWE->first_error_generation = DRS->generation;
                        }
-                       DRWE->last_error_sector = req->sector;
+                       DRWE->last_error_sector = blk_rq_pos(req);
                        DRWE->last_error_generation = DRS->generation;
                }
                spin_lock_irqsave(q->queue_lock, flags);
@@ -2503,24 +2503,23 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
 
        max_sector = transfer_size(ssize,
                                   min(max_sector, max_sector_2),
-                                  current_req->nr_sectors);
+                                  blk_rq_sectors(current_req));
 
        if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
-           buffer_max > fsector_t + current_req->nr_sectors)
+           buffer_max > fsector_t + blk_rq_sectors(current_req))
                current_count_sectors = min_t(int, buffer_max - fsector_t,
-                                             current_req->nr_sectors);
+                                             blk_rq_sectors(current_req));
 
        remaining = current_count_sectors << 9;
 #ifdef FLOPPY_SANITY_CHECK
-       if ((remaining >> 9) > current_req->nr_sectors &&
-           CT(COMMAND) == FD_WRITE) {
+       if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
                DPRINT("in copy buffer\n");
                printk("current_count_sectors=%ld\n", current_count_sectors);
                printk("remaining=%d\n", remaining >> 9);
-               printk("current_req->nr_sectors=%ld\n",
-                      current_req->nr_sectors);
+               printk("current_req->nr_sectors=%u\n",
+                      blk_rq_sectors(current_req));
                printk("current_req->current_nr_sectors=%u\n",
-                      current_req->current_nr_sectors);
+                      blk_rq_cur_sectors(current_req));
                printk("max_sector=%d\n", max_sector);
                printk("ssize=%d\n", ssize);
        }
@@ -2530,7 +2529,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
 
        dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
 
-       size = current_req->current_nr_sectors << 9;
+       size = blk_rq_cur_bytes(current_req);
 
        rq_for_each_segment(bv, current_req, iter) {
                if (!remaining)
@@ -2648,10 +2647,10 @@ static int make_raw_rw_request(void)
 
        max_sector = _floppy->sect * _floppy->head;
 
-       TRACK = (int)current_req->sector / max_sector;
-       fsector_t = (int)current_req->sector % max_sector;
+       TRACK = (int)blk_rq_pos(current_req) / max_sector;
+       fsector_t = (int)blk_rq_pos(current_req) % max_sector;
        if (_floppy->track && TRACK >= _floppy->track) {
-               if (current_req->current_nr_sectors & 1) {
+               if (blk_rq_cur_sectors(current_req) & 1) {
                        current_count_sectors = 1;
                        return 1;
                } else
@@ -2669,7 +2668,7 @@ static int make_raw_rw_request(void)
                if (fsector_t >= max_sector) {
                        current_count_sectors =
                            min_t(int, _floppy->sect - fsector_t,
-                                 current_req->nr_sectors);
+                                 blk_rq_sectors(current_req));
                        return 1;
                }
                SIZECODE = 2;
@@ -2720,7 +2719,7 @@ static int make_raw_rw_request(void)
 
        in_sector_offset = (fsector_t % _floppy->sect) % ssize;
        aligned_sector_t = fsector_t - in_sector_offset;
-       max_size = current_req->nr_sectors;
+       max_size = blk_rq_sectors(current_req);
        if ((raw_cmd->track == buffer_track) &&
            (current_drive == buffer_drive) &&
            (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
@@ -2729,10 +2728,10 @@ static int make_raw_rw_request(void)
                        copy_buffer(1, max_sector, buffer_max);
                        return 1;
                }
-       } else if (in_sector_offset || current_req->nr_sectors < ssize) {
+       } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
                if (CT(COMMAND) == FD_WRITE) {
-                       if (fsector_t + current_req->nr_sectors > ssize &&
-                           fsector_t + current_req->nr_sectors < ssize + ssize)
+                       if (fsector_t + blk_rq_sectors(current_req) > ssize &&
+                           fsector_t + blk_rq_sectors(current_req) < ssize + ssize)
                                max_size = ssize + ssize;
                        else
                                max_size = ssize;
@@ -2776,7 +2775,7 @@ static int make_raw_rw_request(void)
                    (indirect * 2 > direct * 3 &&
                     *errors < DP->max_errors.read_track && ((!probing
                       || (DP->read_track & (1 << DRS->probed_format)))))) {
-                       max_size = current_req->nr_sectors;
+                       max_size = blk_rq_sectors(current_req);
                } else {
                        raw_cmd->kernel_data = current_req->buffer;
                        raw_cmd->length = current_count_sectors << 9;
@@ -2801,7 +2800,7 @@ static int make_raw_rw_request(void)
            fsector_t > buffer_max ||
            fsector_t < buffer_min ||
            ((CT(COMMAND) == FD_READ ||
-             (!in_sector_offset && current_req->nr_sectors >= ssize)) &&
+             (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
             max_sector > 2 * max_buffer_sectors + buffer_min &&
             max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)
            /* not enough space */
@@ -2879,8 +2878,8 @@ static int make_raw_rw_request(void)
                                printk("write\n");
                        return 0;
                }
-       } else if (raw_cmd->length > current_req->nr_sectors << 9 ||
-                  current_count_sectors > current_req->nr_sectors) {
+       } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
+                  current_count_sectors > blk_rq_sectors(current_req)) {
                DPRINT("buffer overrun in direct transfer\n");
                return 0;
        } else if (raw_cmd->length < current_count_sectors << 9) {
@@ -2913,7 +2912,7 @@ static void redo_fd_request(void)
                        struct request *req;
 
                        spin_lock_irq(floppy_queue->queue_lock);
-                       req = elv_next_request(floppy_queue);
+                       req = blk_fetch_request(floppy_queue);
                        spin_unlock_irq(floppy_queue->queue_lock);
                        if (!req) {
                                do_floppy = NULL;
@@ -2990,8 +2989,9 @@ static void do_fd_request(struct request_queue * q)
        if (usage_count == 0) {
                printk("warning: usage count=0, current_req=%p exiting\n",
                       current_req);
-               printk("sect=%ld type=%x flags=%x\n", (long)current_req->sector,
-                      current_req->cmd_type, current_req->cmd_flags);
+               printk("sect=%ld type=%x flags=%x\n",
+                      (long)blk_rq_pos(current_req), current_req->cmd_type,
+                      current_req->cmd_flags);
                return;
        }
        if (test_bit(0, &fdc_busy)) {
@@ -4148,6 +4148,24 @@ static void floppy_device_release(struct device *dev)
 {
 }
 
+static int floppy_resume(struct platform_device *dev)
+{
+       int fdc;
+
+       for (fdc = 0; fdc < N_FDC; fdc++)
+               if (FDCS->address != -1)
+                       user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
+
+       return 0;
+}
+
+static struct platform_driver floppy_driver = {
+       .resume = floppy_resume,
+       .driver = {
+               .name = "floppy",
+       },
+};
+
 static struct platform_device floppy_device[N_DRIVE];
 
 static struct kobject *floppy_find(dev_t dev, int *part, void *data)
@@ -4196,10 +4214,14 @@ static int __init floppy_init(void)
        if (err)
                goto out_put_disk;
 
+       err = platform_driver_register(&floppy_driver);
+       if (err)
+               goto out_unreg_blkdev;
+
        floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
        if (!floppy_queue) {
                err = -ENOMEM;
-               goto out_unreg_blkdev;
+               goto out_unreg_driver;
        }
        blk_queue_max_sectors(floppy_queue, 64);
 
@@ -4346,6 +4368,8 @@ out_flush_work:
 out_unreg_region:
        blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
        blk_cleanup_queue(floppy_queue);
+out_unreg_driver:
+       platform_driver_unregister(&floppy_driver);
 out_unreg_blkdev:
        unregister_blkdev(FLOPPY_MAJOR, "fd");
 out_put_disk:
@@ -4566,6 +4590,7 @@ static void __exit floppy_module_exit(void)
 
        blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
        unregister_blkdev(FLOPPY_MAJOR, "fd");
+       platform_driver_unregister(&floppy_driver);
 
        for (drive = 0; drive < N_DRIVE; drive++) {
                del_timer_sync(&motor_off_timer[drive]);
index baaa9e486e508d354b1818f2ec427c32691c1db9..f65b3f369eb0ce795936045484cfdf9bb7367ac3 100644 (file)
 
 static DEFINE_SPINLOCK(hd_lock);
 static struct request_queue *hd_queue;
+static struct request *hd_req;
 
 #define MAJOR_NR HD_MAJOR
-#define QUEUE (hd_queue)
-#define CURRENT elv_next_request(hd_queue)
 
 #define TIMEOUT_VALUE  (6*HZ)
 #define        HD_DELAY        0
@@ -195,11 +194,24 @@ static void __init hd_setup(char *str, int *ints)
        NR_HD = hdind+1;
 }
 
+static bool hd_end_request(int err, unsigned int bytes)
+{
+       if (__blk_end_request(hd_req, err, bytes))
+               return true;
+       hd_req = NULL;
+       return false;
+}
+
+static bool hd_end_request_cur(int err)
+{
+       return hd_end_request(err, blk_rq_cur_bytes(hd_req));
+}
+
 static void dump_status(const char *msg, unsigned int stat)
 {
        char *name = "hd?";
-       if (CURRENT)
-               name = CURRENT->rq_disk->disk_name;
+       if (hd_req)
+               name = hd_req->rq_disk->disk_name;
 
 #ifdef VERBOSE_ERRORS
        printk("%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
@@ -227,8 +239,8 @@ static void dump_status(const char *msg, unsigned int stat)
                if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
                        printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
                                inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
-                       if (CURRENT)
-                               printk(", sector=%ld", CURRENT->sector);
+                       if (hd_req)
+                               printk(", sector=%ld", blk_rq_pos(hd_req));
                }
                printk("\n");
        }
@@ -406,11 +418,12 @@ static void unexpected_hd_interrupt(void)
  */
 static void bad_rw_intr(void)
 {
-       struct request *req = CURRENT;
+       struct request *req = hd_req;
+
        if (req != NULL) {
                struct hd_i_struct *disk = req->rq_disk->private_data;
                if (++req->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
-                       end_request(req, 0);
+                       hd_end_request_cur(-EIO);
                        disk->special_op = disk->recalibrate = 1;
                } else if (req->errors % RESET_FREQ == 0)
                        reset = 1;
@@ -452,37 +465,30 @@ static void read_intr(void)
        bad_rw_intr();
        hd_request();
        return;
+
 ok_to_read:
-       req = CURRENT;
+       req = hd_req;
        insw(HD_DATA, req->buffer, 256);
-       req->sector++;
-       req->buffer += 512;
-       req->errors = 0;
-       i = --req->nr_sectors;
-       --req->current_nr_sectors;
 #ifdef DEBUG
-       printk("%s: read: sector %ld, remaining = %ld, buffer=%p\n",
-               req->rq_disk->disk_name, req->sector, req->nr_sectors,
-               req->buffer+512);
+       printk("%s: read: sector %ld, remaining = %u, buffer=%p\n",
+              req->rq_disk->disk_name, blk_rq_pos(req) + 1,
+              blk_rq_sectors(req) - 1, req->buffer+512);
 #endif
-       if (req->current_nr_sectors <= 0)
-               end_request(req, 1);
-       if (i > 0) {
+       if (hd_end_request(0, 512)) {
                SET_HANDLER(&read_intr);
                return;
        }
+
        (void) inb_p(HD_STATUS);
 #if (HD_DELAY > 0)
        last_req = read_timer();
 #endif
-       if (elv_next_request(QUEUE))
-               hd_request();
-       return;
+       hd_request();
 }
 
 static void write_intr(void)
 {
-       struct request *req = CURRENT;
+       struct request *req = hd_req;
        int i;
        int retries = 100000;
 
@@ -492,30 +498,25 @@ static void write_intr(void)
                        continue;
                if (!OK_STATUS(i))
                        break;
-               if ((req->nr_sectors <= 1) || (i & DRQ_STAT))
+               if ((blk_rq_sectors(req) <= 1) || (i & DRQ_STAT))
                        goto ok_to_write;
        } while (--retries > 0);
        dump_status("write_intr", i);
        bad_rw_intr();
        hd_request();
        return;
+
 ok_to_write:
-       req->sector++;
-       i = --req->nr_sectors;
-       --req->current_nr_sectors;
-       req->buffer += 512;
-       if (!i || (req->bio && req->current_nr_sectors <= 0))
-               end_request(req, 1);
-       if (i > 0) {
+       if (hd_end_request(0, 512)) {
                SET_HANDLER(&write_intr);
                outsw(HD_DATA, req->buffer, 256);
-       } else {
+               return;
+       }
+
 #if (HD_DELAY > 0)
-               last_req = read_timer();
+       last_req = read_timer();
 #endif
-               hd_request();
-       }
-       return;
+       hd_request();
 }
 
 static void recal_intr(void)
@@ -537,18 +538,18 @@ static void hd_times_out(unsigned long dummy)
 
        do_hd = NULL;
 
-       if (!CURRENT)
+       if (!hd_req)
                return;
 
        spin_lock_irq(hd_queue->queue_lock);
        reset = 1;
-       name = CURRENT->rq_disk->disk_name;
+       name = hd_req->rq_disk->disk_name;
        printk("%s: timeout\n", name);
-       if (++CURRENT->errors >= MAX_ERRORS) {
+       if (++hd_req->errors >= MAX_ERRORS) {
 #ifdef DEBUG
                printk("%s: too many errors\n", name);
 #endif
-               end_request(CURRENT, 0);
+               hd_end_request_cur(-EIO);
        }
        hd_request();
        spin_unlock_irq(hd_queue->queue_lock);
@@ -563,7 +564,7 @@ static int do_special_op(struct hd_i_struct *disk, struct request *req)
        }
        if (disk->head > 16) {
                printk("%s: cannot handle device with more than 16 heads - giving up\n", req->rq_disk->disk_name);
-               end_request(req, 0);
+               hd_end_request_cur(-EIO);
        }
        disk->special_op = 0;
        return 1;
@@ -590,24 +591,27 @@ static void hd_request(void)
 repeat:
        del_timer(&device_timer);
 
-       req = CURRENT;
-       if (!req) {
-               do_hd = NULL;
-               return;
+       if (!hd_req) {
+               hd_req = blk_fetch_request(hd_queue);
+               if (!hd_req) {
+                       do_hd = NULL;
+                       return;
+               }
        }
+       req = hd_req;
 
        if (reset) {
                reset_hd();
                return;
        }
        disk = req->rq_disk->private_data;
-       block = req->sector;
-       nsect = req->nr_sectors;
+       block = blk_rq_pos(req);
+       nsect = blk_rq_sectors(req);
        if (block >= get_capacity(req->rq_disk) ||
            ((block+nsect) > get_capacity(req->rq_disk))) {
                printk("%s: bad access: block=%d, count=%d\n",
                        req->rq_disk->disk_name, block, nsect);
-               end_request(req, 0);
+               hd_end_request_cur(-EIO);
                goto repeat;
        }
 
@@ -647,7 +651,7 @@ repeat:
                        break;
                default:
                        printk("unknown hd-command\n");
-                       end_request(req, 0);
+                       hd_end_request_cur(-EIO);
                        break;
                }
        }
@@ -720,7 +724,7 @@ static int __init hd_init(void)
        blk_queue_max_sectors(hd_queue, 255);
        init_timer(&device_timer);
        device_timer.function = hd_times_out;
-       blk_queue_hardsect_size(hd_queue, 512);
+       blk_queue_logical_block_size(hd_queue, 512);
 
        if (!NR_HD) {
                /*
index ddae80825899ae0459bff4a8109d8fc3468868c3..801f4ab83302556e9b48f1ddf139201a05e8c304 100644 (file)
@@ -511,11 +511,7 @@ out:
  */
 static void loop_add_bio(struct loop_device *lo, struct bio *bio)
 {
-       if (lo->lo_biotail) {
-               lo->lo_biotail->bi_next = bio;
-               lo->lo_biotail = bio;
-       } else
-               lo->lo_bio = lo->lo_biotail = bio;
+       bio_list_add(&lo->lo_bio_list, bio);
 }
 
 /*
@@ -523,16 +519,7 @@ static void loop_add_bio(struct loop_device *lo, struct bio *bio)
  */
 static struct bio *loop_get_bio(struct loop_device *lo)
 {
-       struct bio *bio;
-
-       if ((bio = lo->lo_bio)) {
-               if (bio == lo->lo_biotail)
-                       lo->lo_biotail = NULL;
-               lo->lo_bio = bio->bi_next;
-               bio->bi_next = NULL;
-       }
-
-       return bio;
+       return bio_list_pop(&lo->lo_bio_list);
 }
 
 static int loop_make_request(struct request_queue *q, struct bio *old_bio)
@@ -609,12 +596,13 @@ static int loop_thread(void *data)
 
        set_user_nice(current, -20);
 
-       while (!kthread_should_stop() || lo->lo_bio) {
+       while (!kthread_should_stop() || !bio_list_empty(&lo->lo_bio_list)) {
 
                wait_event_interruptible(lo->lo_event,
-                               lo->lo_bio || kthread_should_stop());
+                               !bio_list_empty(&lo->lo_bio_list) ||
+                               kthread_should_stop());
 
-               if (!lo->lo_bio)
+               if (bio_list_empty(&lo->lo_bio_list))
                        continue;
                spin_lock_irq(&lo->lo_lock);
                bio = loop_get_bio(lo);
@@ -721,10 +709,6 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
        if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
                goto out_putf;
 
-       /* new backing store needs to support loop (eg splice_read) */
-       if (!inode->i_fop->splice_read)
-               goto out_putf;
-
        /* size of the new backing store needs to be the same */
        if (get_loop_size(lo, file) != get_loop_size(lo, old_file))
                goto out_putf;
@@ -800,12 +784,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
        error = -EINVAL;
        if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) {
                const struct address_space_operations *aops = mapping->a_ops;
-               /*
-                * If we can't read - sorry. If we only can't write - well,
-                * it's going to be read-only.
-                */
-               if (!file->f_op->splice_read)
-                       goto out_putf;
+
                if (aops->write_begin)
                        lo_flags |= LO_FLAGS_USE_AOPS;
                if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write)
@@ -841,7 +820,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
        lo->old_gfp_mask = mapping_gfp_mask(mapping);
        mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
 
-       lo->lo_bio = lo->lo_biotail = NULL;
+       bio_list_init(&lo->lo_bio_list);
 
        /*
         * set queue make_request_fn, and add limits based on lower level
index f3898353d0a8f9dc6d328ace0e06689ae366c214..60de5a01e71e6ecd67b15eee29fef7d567265872 100644 (file)
 #include <linux/fs.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
-#include <linux/libata.h>
+#include <linux/ata.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
-#include <linux/mg_disk.h>
 
 #define MG_RES_SEC (CONFIG_MG_DISK_RES << 1)
 
+/* name for block device */
+#define MG_DISK_NAME "mgd"
+/* name for platform device */
+#define MG_DEV_NAME "mg_disk"
+
+#define MG_DISK_MAJ 0
+#define MG_DISK_MAX_PART 16
+#define MG_SECTOR_SIZE 512
+#define MG_MAX_SECTS 256
+
+/* Register offsets */
+#define MG_BUFF_OFFSET                 0x8000
+#define MG_STORAGE_BUFFER_SIZE         0x200
+#define MG_REG_OFFSET                  0xC000
+#define MG_REG_FEATURE                 (MG_REG_OFFSET + 2)     /* write case */
+#define MG_REG_ERROR                   (MG_REG_OFFSET + 2)     /* read case */
+#define MG_REG_SECT_CNT                        (MG_REG_OFFSET + 4)
+#define MG_REG_SECT_NUM                        (MG_REG_OFFSET + 6)
+#define MG_REG_CYL_LOW                 (MG_REG_OFFSET + 8)
+#define MG_REG_CYL_HIGH                        (MG_REG_OFFSET + 0xA)
+#define MG_REG_DRV_HEAD                        (MG_REG_OFFSET + 0xC)
+#define MG_REG_COMMAND                 (MG_REG_OFFSET + 0xE)   /* write case */
+#define MG_REG_STATUS                  (MG_REG_OFFSET + 0xE)   /* read  case */
+#define MG_REG_DRV_CTRL                        (MG_REG_OFFSET + 0x10)
+#define MG_REG_BURST_CTRL              (MG_REG_OFFSET + 0x12)
+
+/* handy status */
+#define MG_STAT_READY  (ATA_DRDY | ATA_DSC)
+#define MG_READY_OK(s) (((s) & (MG_STAT_READY | (ATA_BUSY | ATA_DF | \
+                                ATA_ERR))) == MG_STAT_READY)
+
+/* error code for others */
+#define MG_ERR_NONE            0
+#define MG_ERR_TIMEOUT         0x100
+#define MG_ERR_INIT_STAT       0x101
+#define MG_ERR_TRANSLATION     0x102
+#define MG_ERR_CTRL_RST                0x103
+#define MG_ERR_INV_STAT                0x104
+#define MG_ERR_RSTOUT          0x105
+
+#define MG_MAX_ERRORS  6       /* Max read/write errors */
+
+/* command */
+#define MG_CMD_RD 0x20
+#define MG_CMD_WR 0x30
+#define MG_CMD_SLEEP 0x99
+#define MG_CMD_WAKEUP 0xC3
+#define MG_CMD_ID 0xEC
+#define MG_CMD_WR_CONF 0x3C
+#define MG_CMD_RD_CONF 0x40
+
+/* operation mode */
+#define MG_OP_CASCADE (1 << 0)
+#define MG_OP_CASCADE_SYNC_RD (1 << 1)
+#define MG_OP_CASCADE_SYNC_WR (1 << 2)
+#define MG_OP_INTERLEAVE (1 << 3)
+
+/* synchronous */
+#define MG_BURST_LAT_4 (3 << 4)
+#define MG_BURST_LAT_5 (4 << 4)
+#define MG_BURST_LAT_6 (5 << 4)
+#define MG_BURST_LAT_7 (6 << 4)
+#define MG_BURST_LAT_8 (7 << 4)
+#define MG_BURST_LEN_4 (1 << 1)
+#define MG_BURST_LEN_8 (2 << 1)
+#define MG_BURST_LEN_16 (3 << 1)
+#define MG_BURST_LEN_32 (4 << 1)
+#define MG_BURST_LEN_CONT (0 << 1)
+
+/* timeout value (unit: ms) */
+#define MG_TMAX_CONF_TO_CMD    1
+#define MG_TMAX_WAIT_RD_DRQ    10
+#define MG_TMAX_WAIT_WR_DRQ    500
+#define MG_TMAX_RST_TO_BUSY    10
+#define MG_TMAX_HDRST_TO_RDY   500
+#define MG_TMAX_SWRST_TO_RDY   500
+#define MG_TMAX_RSTOUT         3000
+
+/* device attribution */
+/* use mflash as boot device */
+#define MG_BOOT_DEV            (1 << 0)
+/* use mflash as storage device */
+#define MG_STORAGE_DEV         (1 << 1)
+/* same as MG_STORAGE_DEV, but bootloader already done reset sequence */
+#define MG_STORAGE_DEV_SKIP_RST        (1 << 2)
+
+#define MG_DEV_MASK (MG_BOOT_DEV | MG_STORAGE_DEV | MG_STORAGE_DEV_SKIP_RST)
+
+/* names of GPIO resource */
+#define MG_RST_PIN     "mg_rst"
+/* except MG_BOOT_DEV, reset-out pin should be assigned */
+#define MG_RSTOUT_PIN  "mg_rstout"
+
+/* private driver data */
+struct mg_drv_data {
+       /* disk resource */
+       u32 use_polling;
+
+       /* device attribution */
+       u32 dev_attr;
+
+       /* internally used */
+       struct mg_host *host;
+};
+
+/* main structure for mflash driver */
+struct mg_host {
+       struct device *dev;
+
+       struct request_queue *breq;
+       struct request *req;
+       spinlock_t lock;
+       struct gendisk *gd;
+
+       struct timer_list timer;
+       void (*mg_do_intr) (struct mg_host *);
+
+       u16 id[ATA_ID_WORDS];
+
+       u16 cyls;
+       u16 heads;
+       u16 sectors;
+       u32 n_sectors;
+       u32 nres_sectors;
+
+       void __iomem *dev_base;
+       unsigned int irq;
+       unsigned int rst;
+       unsigned int rstout;
+
+       u32 major;
+       u32 error;
+};
+
+/*
+ * Debugging macro and defines
+ */
+#undef DO_MG_DEBUG
+#ifdef DO_MG_DEBUG
+#  define MG_DBG(fmt, args...) \
+       printk(KERN_DEBUG "%s:%d "fmt, __func__, __LINE__, ##args)
+#else /* CONFIG_MG_DEBUG */
+#  define MG_DBG(fmt, args...) do { } while (0)
+#endif /* CONFIG_MG_DEBUG */
+
 static void mg_request(struct request_queue *);
 
+static bool mg_end_request(struct mg_host *host, int err, unsigned int nr_bytes)
+{
+       if (__blk_end_request(host->req, err, nr_bytes))
+               return true;
+
+       host->req = NULL;
+       return false;
+}
+
+static bool mg_end_request_cur(struct mg_host *host, int err)
+{
+       return mg_end_request(host, err, blk_rq_cur_bytes(host->req));
+}
+
 static void mg_dump_status(const char *msg, unsigned int stat,
                struct mg_host *host)
 {
        char *name = MG_DISK_NAME;
-       struct request *req;
 
-       if (host->breq) {
-               req = elv_next_request(host->breq);
-               if (req)
-                       name = req->rq_disk->disk_name;
-       }
+       if (host->req)
+               name = host->req->rq_disk->disk_name;
 
        printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
-       if (stat & MG_REG_STATUS_BIT_BUSY)
+       if (stat & ATA_BUSY)
                printk("Busy ");
-       if (stat & MG_REG_STATUS_BIT_READY)
+       if (stat & ATA_DRDY)
                printk("DriveReady ");
-       if (stat & MG_REG_STATUS_BIT_WRITE_FAULT)
+       if (stat & ATA_DF)
                printk("WriteFault ");
-       if (stat & MG_REG_STATUS_BIT_SEEK_DONE)
+       if (stat & ATA_DSC)
                printk("SeekComplete ");
-       if (stat & MG_REG_STATUS_BIT_DATA_REQ)
+       if (stat & ATA_DRQ)
                printk("DataRequest ");
-       if (stat & MG_REG_STATUS_BIT_CORRECTED_ERROR)
+       if (stat & ATA_CORR)
                printk("CorrectedError ");
-       if (stat & MG_REG_STATUS_BIT_ERROR)
+       if (stat & ATA_ERR)
                printk("Error ");
        printk("}\n");
-       if ((stat & MG_REG_STATUS_BIT_ERROR) == 0) {
+       if ((stat & ATA_ERR) == 0) {
                host->error = 0;
        } else {
                host->error = inb((unsigned long)host->dev_base + MG_REG_ERROR);
                printk(KERN_ERR "%s: %s: error=0x%02x { ", name, msg,
                                host->error & 0xff);
-               if (host->error & MG_REG_ERR_BBK)
+               if (host->error & ATA_BBK)
                        printk("BadSector ");
-               if (host->error & MG_REG_ERR_UNC)
+               if (host->error & ATA_UNC)
                        printk("UncorrectableError ");
-               if (host->error & MG_REG_ERR_IDNF)
+               if (host->error & ATA_IDNF)
                        printk("SectorIdNotFound ");
-               if (host->error & MG_REG_ERR_ABRT)
+               if (host->error & ATA_ABORTED)
                        printk("DriveStatusError ");
-               if (host->error & MG_REG_ERR_AMNF)
+               if (host->error & ATA_AMNF)
                        printk("AddrMarkNotFound ");
                printk("}");
-               if (host->error &
-                               (MG_REG_ERR_BBK | MG_REG_ERR_UNC |
-                                MG_REG_ERR_IDNF | MG_REG_ERR_AMNF)) {
-                       if (host->breq) {
-                               req = elv_next_request(host->breq);
-                               if (req)
-                                       printk(", sector=%u", (u32)req->sector);
-                       }
-
+               if (host->error & (ATA_BBK | ATA_UNC | ATA_IDNF | ATA_AMNF)) {
+                       if (host->req)
+                               printk(", sector=%u",
+                                      (unsigned int)blk_rq_pos(host->req));
                }
                printk("\n");
        }
@@ -100,12 +249,12 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec)
 
        do {
                cur_jiffies = jiffies;
-               if (status & MG_REG_STATUS_BIT_BUSY) {
-                       if (expect == MG_REG_STATUS_BIT_BUSY)
+               if (status & ATA_BUSY) {
+                       if (expect == ATA_BUSY)
                                break;
                } else {
                        /* Check the error condition! */
-                       if (status & MG_REG_STATUS_BIT_ERROR) {
+                       if (status & ATA_ERR) {
                                mg_dump_status("mg_wait", status, host);
                                break;
                        }
@@ -114,8 +263,8 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec)
                                if (MG_READY_OK(status))
                                        break;
 
-                       if (expect == MG_REG_STATUS_BIT_DATA_REQ)
-                               if (status & MG_REG_STATUS_BIT_DATA_REQ)
+                       if (expect == ATA_DRQ)
+                               if (status & ATA_DRQ)
                                        break;
                }
                if (!msec) {
@@ -173,6 +322,42 @@ static irqreturn_t mg_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+/* local copy of ata_id_string() */
+static void mg_id_string(const u16 *id, unsigned char *s,
+                        unsigned int ofs, unsigned int len)
+{
+       unsigned int c;
+
+       BUG_ON(len & 1);
+
+       while (len > 0) {
+               c = id[ofs] >> 8;
+               *s = c;
+               s++;
+
+               c = id[ofs] & 0xff;
+               *s = c;
+               s++;
+
+               ofs++;
+               len -= 2;
+       }
+}
+
+/* local copy of ata_id_c_string() */
+static void mg_id_c_string(const u16 *id, unsigned char *s,
+                          unsigned int ofs, unsigned int len)
+{
+       unsigned char *p;
+
+       mg_id_string(id, s, ofs, len - 1);
+
+       p = s + strnlen(s, len - 1);
+       while (p > s && p[-1] == ' ')
+               p--;
+       *p = '\0';
+}
+
 static int mg_get_disk_id(struct mg_host *host)
 {
        u32 i;
@@ -184,12 +369,10 @@ static int mg_get_disk_id(struct mg_host *host)
        char serial[ATA_ID_SERNO_LEN + 1];
 
        if (!prv_data->use_polling)
-               outb(MG_REG_CTRL_INTR_DISABLE,
-                               (unsigned long)host->dev_base +
-                               MG_REG_DRV_CTRL);
+               outb(ATA_NIEN, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
 
        outb(MG_CMD_ID, (unsigned long)host->dev_base + MG_REG_COMMAND);
-       err = mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, MG_TMAX_WAIT_RD_DRQ);
+       err = mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_RD_DRQ);
        if (err)
                return err;
 
@@ -219,9 +402,9 @@ static int mg_get_disk_id(struct mg_host *host)
                host->n_sectors -= host->nres_sectors;
        }
 
-       ata_id_c_string(id, fwrev, ATA_ID_FW_REV, sizeof(fwrev));
-       ata_id_c_string(id, model, ATA_ID_PROD, sizeof(model));
-       ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
+       mg_id_c_string(id, fwrev, ATA_ID_FW_REV, sizeof(fwrev));
+       mg_id_c_string(id, model, ATA_ID_PROD, sizeof(model));
+       mg_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
        printk(KERN_INFO "mg_disk: model: %s\n", model);
        printk(KERN_INFO "mg_disk: firm: %.8s\n", fwrev);
        printk(KERN_INFO "mg_disk: serial: %s\n", serial);
@@ -229,8 +412,7 @@ static int mg_get_disk_id(struct mg_host *host)
                        host->n_sectors, host->nres_sectors);
 
        if (!prv_data->use_polling)
-               outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base +
-                               MG_REG_DRV_CTRL);
+               outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
 
        return err;
 }
@@ -244,7 +426,7 @@ static int mg_disk_init(struct mg_host *host)
 
        /* hdd rst low */
        gpio_set_value(host->rst, 0);
-       err = mg_wait(host, MG_REG_STATUS_BIT_BUSY, MG_TMAX_RST_TO_BUSY);
+       err = mg_wait(host, ATA_BUSY, MG_TMAX_RST_TO_BUSY);
        if (err)
                return err;
 
@@ -255,17 +437,14 @@ static int mg_disk_init(struct mg_host *host)
                return err;
 
        /* soft reset on */
-       outb(MG_REG_CTRL_RESET |
-                       (prv_data->use_polling ? MG_REG_CTRL_INTR_DISABLE :
-                        MG_REG_CTRL_INTR_ENABLE),
+       outb(ATA_SRST | (prv_data->use_polling ? ATA_NIEN : 0),
                        (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
-       err = mg_wait(host, MG_REG_STATUS_BIT_BUSY, MG_TMAX_RST_TO_BUSY);
+       err = mg_wait(host, ATA_BUSY, MG_TMAX_RST_TO_BUSY);
        if (err)
                return err;
 
        /* soft reset off */
-       outb(prv_data->use_polling ? MG_REG_CTRL_INTR_DISABLE :
-                       MG_REG_CTRL_INTR_ENABLE,
+       outb(prv_data->use_polling ? ATA_NIEN : 0,
                        (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
        err = mg_wait(host, MG_STAT_READY, MG_TMAX_SWRST_TO_RDY);
        if (err)
@@ -281,11 +460,10 @@ static int mg_disk_init(struct mg_host *host)
 
 static void mg_bad_rw_intr(struct mg_host *host)
 {
-       struct request *req = elv_next_request(host->breq);
-       if (req != NULL)
-               if (++req->errors >= MG_MAX_ERRORS ||
-                               host->error == MG_ERR_TIMEOUT)
-                       end_request(req, 0);
+       if (host->req)
+               if (++host->req->errors >= MG_MAX_ERRORS ||
+                   host->error == MG_ERR_TIMEOUT)
+                       mg_end_request_cur(host, -EIO);
 }
 
 static unsigned int mg_out(struct mg_host *host,
@@ -311,7 +489,7 @@ static unsigned int mg_out(struct mg_host *host,
                        MG_REG_CYL_LOW);
        outb((u8)(sect_num >> 16), (unsigned long)host->dev_base +
                        MG_REG_CYL_HIGH);
-       outb((u8)((sect_num >> 24) | MG_REG_HEAD_LBA_MODE),
+       outb((u8)((sect_num >> 24) | ATA_LBA | ATA_DEVICE_OBS),
                        (unsigned long)host->dev_base + MG_REG_DRV_HEAD);
        outb(cmd, (unsigned long)host->dev_base + MG_REG_COMMAND);
        return MG_ERR_NONE;
@@ -319,105 +497,77 @@ static unsigned int mg_out(struct mg_host *host,
 
 static void mg_read(struct request *req)
 {
-       u32 remains, j;
+       u32 j;
        struct mg_host *host = req->rq_disk->private_data;
 
-       remains = req->nr_sectors;
-
-       if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_RD, NULL) !=
-                       MG_ERR_NONE)
+       if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req),
+                  MG_CMD_RD, NULL) != MG_ERR_NONE)
                mg_bad_rw_intr(host);
 
        MG_DBG("requested %d sects (from %ld), buffer=0x%p\n",
-                       remains, req->sector, req->buffer);
+              blk_rq_sectors(req), blk_rq_pos(req), req->buffer);
+
+       do {
+               u16 *buff = (u16 *)req->buffer;
 
-       while (remains) {
-               if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ,
-                                       MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) {
+               if (mg_wait(host, ATA_DRQ,
+                           MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) {
                        mg_bad_rw_intr(host);
                        return;
                }
-               for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
-                       *(u16 *)req->buffer =
-                               inw((unsigned long)host->dev_base +
-                                               MG_BUFF_OFFSET + (j << 1));
-                       req->buffer += 2;
-               }
-
-               req->sector++;
-               req->errors = 0;
-               remains = --req->nr_sectors;
-               --req->current_nr_sectors;
-
-               if (req->current_nr_sectors <= 0) {
-                       MG_DBG("remain : %d sects\n", remains);
-                       end_request(req, 1);
-                       if (remains > 0)
-                               req = elv_next_request(host->breq);
-               }
+               for (j = 0; j < MG_SECTOR_SIZE >> 1; j++)
+                       *buff++ = inw((unsigned long)host->dev_base +
+                                     MG_BUFF_OFFSET + (j << 1));
 
                outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base +
                                MG_REG_COMMAND);
-       }
+       } while (mg_end_request(host, 0, MG_SECTOR_SIZE));
 }
 
 static void mg_write(struct request *req)
 {
-       u32 remains, j;
+       u32 j;
        struct mg_host *host = req->rq_disk->private_data;
 
-       remains = req->nr_sectors;
-
-       if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_WR, NULL) !=
-                       MG_ERR_NONE) {
+       if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req),
+                  MG_CMD_WR, NULL) != MG_ERR_NONE) {
                mg_bad_rw_intr(host);
                return;
        }
 
-
        MG_DBG("requested %d sects (from %ld), buffer=0x%p\n",
-                       remains, req->sector, req->buffer);
-       while (remains) {
-               if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ,
-                                       MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) {
+              blk_rq_sectors(req), blk_rq_pos(req), req->buffer);
+
+       do {
+               u16 *buff = (u16 *)req->buffer;
+
+       if (mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) {
                        mg_bad_rw_intr(host);
                        return;
                }
-               for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
-                       outw(*(u16 *)req->buffer,
-                                       (unsigned long)host->dev_base +
-                                       MG_BUFF_OFFSET + (j << 1));
-                       req->buffer += 2;
-               }
-               req->sector++;
-               remains = --req->nr_sectors;
-               --req->current_nr_sectors;
-
-               if (req->current_nr_sectors <= 0) {
-                       MG_DBG("remain : %d sects\n", remains);
-                       end_request(req, 1);
-                       if (remains > 0)
-                               req = elv_next_request(host->breq);
-               }
+               for (j = 0; j < MG_SECTOR_SIZE >> 1; j++)
+                       outw(*buff++, (unsigned long)host->dev_base +
+                                     MG_BUFF_OFFSET + (j << 1));
 
                outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base +
                                MG_REG_COMMAND);
-       }
+       } while (mg_end_request(host, 0, MG_SECTOR_SIZE));
 }
 
 static void mg_read_intr(struct mg_host *host)
 {
+       struct request *req = host->req;
        u32 i;
-       struct request *req;
+       u16 *buff;
 
        /* check status */
        do {
                i = inb((unsigned long)host->dev_base + MG_REG_STATUS);
-               if (i & MG_REG_STATUS_BIT_BUSY)
+               if (i & ATA_BUSY)
                        break;
                if (!MG_READY_OK(i))
                        break;
-               if (i & MG_REG_STATUS_BIT_DATA_REQ)
+               if (i & ATA_DRQ)
                        goto ok_to_read;
        } while (0);
        mg_dump_status("mg_read_intr", i, host);
@@ -427,60 +577,42 @@ static void mg_read_intr(struct mg_host *host)
 
 ok_to_read:
        /* get current segment of request */
-       req = elv_next_request(host->breq);
+       buff = (u16 *)req->buffer;
 
        /* read 1 sector */
-       for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) {
-               *(u16 *)req->buffer =
-                       inw((unsigned long)host->dev_base + MG_BUFF_OFFSET +
-                                       (i << 1));
-               req->buffer += 2;
-       }
+       for (i = 0; i < MG_SECTOR_SIZE >> 1; i++)
+               *buff++ = inw((unsigned long)host->dev_base + MG_BUFF_OFFSET +
+                             (i << 1));
 
-       /* manipulate request */
        MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n",
-                       req->sector, req->nr_sectors - 1, req->buffer);
-
-       req->sector++;
-       req->errors = 0;
-       i = --req->nr_sectors;
-       --req->current_nr_sectors;
-
-       /* let know if current segment done */
-       if (req->current_nr_sectors <= 0)
-               end_request(req, 1);
-
-       /* set handler if read remains */
-       if (i > 0) {
-               host->mg_do_intr = mg_read_intr;
-               mod_timer(&host->timer, jiffies + 3 * HZ);
-       }
+              blk_rq_pos(req), blk_rq_sectors(req) - 1, req->buffer);
 
        /* send read confirm */
        outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND);
 
-       /* goto next request */
-       if (!i)
+       if (mg_end_request(host, 0, MG_SECTOR_SIZE)) {
+               /* set handler if read remains */
+               host->mg_do_intr = mg_read_intr;
+               mod_timer(&host->timer, jiffies + 3 * HZ);
+       } else /* goto next request */
                mg_request(host->breq);
 }
 
 static void mg_write_intr(struct mg_host *host)
 {
+       struct request *req = host->req;
        u32 i, j;
        u16 *buff;
-       struct request *req;
-
-       /* get current segment of request */
-       req = elv_next_request(host->breq);
+       bool rem;
 
        /* check status */
        do {
                i = inb((unsigned long)host->dev_base + MG_REG_STATUS);
-               if (i & MG_REG_STATUS_BIT_BUSY)
+               if (i & ATA_BUSY)
                        break;
                if (!MG_READY_OK(i))
                        break;
-               if ((req->nr_sectors <= 1) || (i & MG_REG_STATUS_BIT_DATA_REQ))
+               if ((blk_rq_sectors(req) <= 1) || (i & ATA_DRQ))
                        goto ok_to_write;
        } while (0);
        mg_dump_status("mg_write_intr", i, host);
@@ -489,18 +621,8 @@ static void mg_write_intr(struct mg_host *host)
        return;
 
 ok_to_write:
-       /* manipulate request */
-       req->sector++;
-       i = --req->nr_sectors;
-       --req->current_nr_sectors;
-       req->buffer += MG_SECTOR_SIZE;
-
-       /* let know if current segment or all done */
-       if (!i || (req->bio && req->current_nr_sectors <= 0))
-               end_request(req, 1);
-
-       /* write 1 sector and set handler if remains */
-       if (i > 0) {
+       if ((rem = mg_end_request(host, 0, MG_SECTOR_SIZE))) {
+               /* write 1 sector and set handler if remains */
                buff = (u16 *)req->buffer;
                for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) {
                        outw(*buff, (unsigned long)host->dev_base +
@@ -508,7 +630,7 @@ ok_to_write:
                        buff++;
                }
                MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n",
-                               req->sector, req->nr_sectors, req->buffer);
+                      blk_rq_pos(req), blk_rq_sectors(req), req->buffer);
                host->mg_do_intr = mg_write_intr;
                mod_timer(&host->timer, jiffies + 3 * HZ);
        }
@@ -516,7 +638,7 @@ ok_to_write:
        /* send write confirm */
        outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND);
 
-       if (!i)
+       if (!rem)
                mg_request(host->breq);
 }
 
@@ -524,49 +646,45 @@ void mg_times_out(unsigned long data)
 {
        struct mg_host *host = (struct mg_host *)data;
        char *name;
-       struct request *req;
 
        spin_lock_irq(&host->lock);
 
-       req = elv_next_request(host->breq);
-       if (!req)
+       if (!host->req)
                goto out_unlock;
 
        host->mg_do_intr = NULL;
 
-       name = req->rq_disk->disk_name;
+       name = host->req->rq_disk->disk_name;
        printk(KERN_DEBUG "%s: timeout\n", name);
 
        host->error = MG_ERR_TIMEOUT;
        mg_bad_rw_intr(host);
 
-       mg_request(host->breq);
 out_unlock:
+       mg_request(host->breq);
        spin_unlock_irq(&host->lock);
 }
 
 static void mg_request_poll(struct request_queue *q)
 {
-       struct request *req;
-       struct mg_host *host;
+       struct mg_host *host = q->queuedata;
 
-       while ((req = elv_next_request(q)) != NULL) {
-               host = req->rq_disk->private_data;
-               if (blk_fs_request(req)) {
-                       switch (rq_data_dir(req)) {
-                       case READ:
-                               mg_read(req);
-                               break;
-                       case WRITE:
-                               mg_write(req);
-                               break;
-                       default:
-                               printk(KERN_WARNING "%s:%d unknown command\n",
-                                               __func__, __LINE__);
-                               end_request(req, 0);
+       while (1) {
+               if (!host->req) {
+                       host->req = blk_fetch_request(q);
+                       if (!host->req)
                                break;
-                       }
                }
+
+               if (unlikely(!blk_fs_request(host->req))) {
+                       mg_end_request_cur(host, -EIO);
+                       continue;
+               }
+
+               if (rq_data_dir(host->req) == READ)
+                       mg_read(host->req);
+               else
+                       mg_write(host->req);
        }
 }
 
@@ -588,18 +706,15 @@ static unsigned int mg_issue_req(struct request *req,
                break;
        case WRITE:
                /* TODO : handler */
-               outb(MG_REG_CTRL_INTR_DISABLE,
-                               (unsigned long)host->dev_base +
-                               MG_REG_DRV_CTRL);
+               outb(ATA_NIEN, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
                if (mg_out(host, sect_num, sect_cnt, MG_CMD_WR, &mg_write_intr)
                                != MG_ERR_NONE) {
                        mg_bad_rw_intr(host);
                        return host->error;
                }
                del_timer(&host->timer);
-               mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, MG_TMAX_WAIT_WR_DRQ);
-               outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base +
-                               MG_REG_DRV_CTRL);
+               mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_WR_DRQ);
+               outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
                if (host->error) {
                        mg_bad_rw_intr(host);
                        return host->error;
@@ -614,11 +729,6 @@ static unsigned int mg_issue_req(struct request *req,
                outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base +
                                MG_REG_COMMAND);
                break;
-       default:
-               printk(KERN_WARNING "%s:%d unknown command\n",
-                               __func__, __LINE__);
-               end_request(req, 0);
-               break;
        }
        return MG_ERR_NONE;
 }
@@ -626,16 +736,17 @@ static unsigned int mg_issue_req(struct request *req,
 /* This function also called from IRQ context */
 static void mg_request(struct request_queue *q)
 {
+       struct mg_host *host = q->queuedata;
        struct request *req;
-       struct mg_host *host;
        u32 sect_num, sect_cnt;
 
        while (1) {
-               req = elv_next_request(q);
-               if (!req)
-                       return;
-
-               host = req->rq_disk->private_data;
+               if (!host->req) {
+                       host->req = blk_fetch_request(q);
+                       if (!host->req)
+                               break;
+               }
+               req = host->req;
 
                /* check unwanted request call */
                if (host->mg_do_intr)
@@ -643,9 +754,9 @@ static void mg_request(struct request_queue *q)
 
                del_timer(&host->timer);
 
-               sect_num = req->sector;
+               sect_num = blk_rq_pos(req);
                /* deal whole segments */
-               sect_cnt = req->nr_sectors;
+               sect_cnt = blk_rq_sectors(req);
 
                /* sanity check */
                if (sect_num >= get_capacity(req->rq_disk) ||
@@ -655,12 +766,14 @@ static void mg_request(struct request_queue *q)
                                        "%s: bad access: sector=%d, count=%d\n",
                                        req->rq_disk->disk_name,
                                        sect_num, sect_cnt);
-                       end_request(req, 0);
+                       mg_end_request_cur(host, -EIO);
                        continue;
                }
 
-               if (!blk_fs_request(req))
-                       return;
+               if (unlikely(!blk_fs_request(req))) {
+                       mg_end_request_cur(host, -EIO);
+                       continue;
+               }
 
                if (!mg_issue_req(req, host, sect_num, sect_cnt))
                        return;
@@ -690,9 +803,7 @@ static int mg_suspend(struct platform_device *plat_dev, pm_message_t state)
                return -EIO;
 
        if (!prv_data->use_polling)
-               outb(MG_REG_CTRL_INTR_DISABLE,
-                               (unsigned long)host->dev_base +
-                               MG_REG_DRV_CTRL);
+               outb(ATA_NIEN, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
 
        outb(MG_CMD_SLEEP, (unsigned long)host->dev_base + MG_REG_COMMAND);
        /* wait until mflash deep sleep */
@@ -700,9 +811,7 @@ static int mg_suspend(struct platform_device *plat_dev, pm_message_t state)
 
        if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD)) {
                if (!prv_data->use_polling)
-                       outb(MG_REG_CTRL_INTR_ENABLE,
-                                       (unsigned long)host->dev_base +
-                                       MG_REG_DRV_CTRL);
+                       outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
                return -EIO;
        }
 
@@ -725,8 +834,7 @@ static int mg_resume(struct platform_device *plat_dev)
                return -EIO;
 
        if (!prv_data->use_polling)
-               outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base +
-                               MG_REG_DRV_CTRL);
+               outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
 
        return 0;
 }
@@ -877,6 +985,7 @@ static int mg_probe(struct platform_device *plat_dev)
                                __func__, __LINE__);
                goto probe_err_5;
        }
+       host->breq->queuedata = host;
 
        /* mflash is random device, thanx for the noop */
        elevator_exit(host->breq->elevator);
@@ -887,7 +996,7 @@ static int mg_probe(struct platform_device *plat_dev)
                goto probe_err_6;
        }
        blk_queue_max_sectors(host->breq, MG_MAX_SECTS);
-       blk_queue_hardsect_size(host->breq, MG_SECTOR_SIZE);
+       blk_queue_logical_block_size(host->breq, MG_SECTOR_SIZE);
 
        init_timer(&host->timer);
        host->timer.function = mg_times_out;
index 4d6de4f15ccb34dd4039ed4bf3e53b5993751958..5d23ffad7c77fc31d97ff1d5e3fed081dffe16c3 100644 (file)
@@ -110,7 +110,7 @@ static void nbd_end_request(struct request *req)
                        req, error ? "failed" : "done");
 
        spin_lock_irqsave(q->queue_lock, flags);
-       __blk_end_request(req, error, req->nr_sectors << 9);
+       __blk_end_request_all(req, error);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
@@ -231,19 +231,19 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req)
 {
        int result, flags;
        struct nbd_request request;
-       unsigned long size = req->nr_sectors << 9;
+       unsigned long size = blk_rq_bytes(req);
 
        request.magic = htonl(NBD_REQUEST_MAGIC);
        request.type = htonl(nbd_cmd(req));
-       request.from = cpu_to_be64((u64) req->sector << 9);
+       request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9);
        request.len = htonl(size);
        memcpy(request.handle, &req, sizeof(req));
 
-       dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB)\n",
+       dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%uB)\n",
                        lo->disk->disk_name, req,
                        nbdcmd_to_ascii(nbd_cmd(req)),
-                       (unsigned long long)req->sector << 9,
-                       req->nr_sectors << 9);
+                       (unsigned long long)blk_rq_pos(req) << 9,
+                       blk_rq_bytes(req));
        result = sock_xmit(lo, 1, &request, sizeof(request),
                        (nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0);
        if (result <= 0) {
@@ -533,11 +533,9 @@ static void do_nbd_request(struct request_queue *q)
 {
        struct request *req;
        
-       while ((req = elv_next_request(q)) != NULL) {
+       while ((req = blk_fetch_request(q)) != NULL) {
                struct nbd_device *lo;
 
-               blkdev_dequeue_request(req);
-
                spin_unlock_irq(q->queue_lock);
 
                dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n",
@@ -580,13 +578,6 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
                blk_rq_init(NULL, &sreq);
                sreq.cmd_type = REQ_TYPE_SPECIAL;
                nbd_cmd(&sreq) = NBD_CMD_DISC;
-               /*
-                * Set these to sane values in case server implementation
-                * fails to check the request type first and also to keep
-                * debugging output cleaner.
-                */
-               sreq.sector = 0;
-               sreq.nr_sectors = 0;
                if (!lo->sock)
                        return -EINVAL;
                nbd_send_req(lo, &sreq);
index e91d4b4b014fc5997ce88ef3edbf09366cb95a80..911dfd98d813cf7ad23cdc44a77aad946580bfe0 100644 (file)
@@ -719,32 +719,37 @@ static void do_pcd_request(struct request_queue * q)
        if (pcd_busy)
                return;
        while (1) {
-               pcd_req = elv_next_request(q);
-               if (!pcd_req)
-                       return;
+               if (!pcd_req) {
+                       pcd_req = blk_fetch_request(q);
+                       if (!pcd_req)
+                               return;
+               }
 
                if (rq_data_dir(pcd_req) == READ) {
                        struct pcd_unit *cd = pcd_req->rq_disk->private_data;
                        if (cd != pcd_current)
                                pcd_bufblk = -1;
                        pcd_current = cd;
-                       pcd_sector = pcd_req->sector;
-                       pcd_count = pcd_req->current_nr_sectors;
+                       pcd_sector = blk_rq_pos(pcd_req);
+                       pcd_count = blk_rq_cur_sectors(pcd_req);
                        pcd_buf = pcd_req->buffer;
                        pcd_busy = 1;
                        ps_set_intr(do_pcd_read, NULL, 0, nice);
                        return;
-               } else
-                       end_request(pcd_req, 0);
+               } else {
+                       __blk_end_request_all(pcd_req, -EIO);
+                       pcd_req = NULL;
+               }
        }
 }
 
-static inline void next_request(int success)
+static inline void next_request(int err)
 {
        unsigned long saved_flags;
 
        spin_lock_irqsave(&pcd_lock, saved_flags);
-       end_request(pcd_req, success);
+       if (!__blk_end_request_cur(pcd_req, err))
+               pcd_req = NULL;
        pcd_busy = 0;
        do_pcd_request(pcd_queue);
        spin_unlock_irqrestore(&pcd_lock, saved_flags);
@@ -781,7 +786,7 @@ static void pcd_start(void)
 
        if (pcd_command(pcd_current, rd_cmd, 2048, "read block")) {
                pcd_bufblk = -1;
-               next_request(0);
+               next_request(-EIO);
                return;
        }
 
@@ -796,7 +801,7 @@ static void do_pcd_read(void)
        pcd_retries = 0;
        pcd_transfer();
        if (!pcd_count) {
-               next_request(1);
+               next_request(0);
                return;
        }
 
@@ -815,7 +820,7 @@ static void do_pcd_read_drq(void)
                        return;
                }
                pcd_bufblk = -1;
-               next_request(0);
+               next_request(-EIO);
                return;
        }
 
index 9299455b0af678d3176a9c7a431f544583e13faa..bf5955b3d873511d25e31c162d7ee4280a6cc14c 100644 (file)
@@ -410,10 +410,12 @@ static void run_fsm(void)
                                pd_claimed = 0;
                                phase = NULL;
                                spin_lock_irqsave(&pd_lock, saved_flags);
-                               end_request(pd_req, res);
-                               pd_req = elv_next_request(pd_queue);
-                               if (!pd_req)
-                                       stop = 1;
+                               if (!__blk_end_request_cur(pd_req,
+                                               res == Ok ? 0 : -EIO)) {
+                                       pd_req = blk_fetch_request(pd_queue);
+                                       if (!pd_req)
+                                               stop = 1;
+                               }
                                spin_unlock_irqrestore(&pd_lock, saved_flags);
                                if (stop)
                                        return;
@@ -443,11 +445,11 @@ static enum action do_pd_io_start(void)
 
        pd_cmd = rq_data_dir(pd_req);
        if (pd_cmd == READ || pd_cmd == WRITE) {
-               pd_block = pd_req->sector;
-               pd_count = pd_req->current_nr_sectors;
+               pd_block = blk_rq_pos(pd_req);
+               pd_count = blk_rq_cur_sectors(pd_req);
                if (pd_block + pd_count > get_capacity(pd_req->rq_disk))
                        return Fail;
-               pd_run = pd_req->nr_sectors;
+               pd_run = blk_rq_sectors(pd_req);
                pd_buf = pd_req->buffer;
                pd_retries = 0;
                if (pd_cmd == READ)
@@ -477,8 +479,8 @@ static int pd_next_buf(void)
        if (pd_count)
                return 0;
        spin_lock_irqsave(&pd_lock, saved_flags);
-       end_request(pd_req, 1);
-       pd_count = pd_req->current_nr_sectors;
+       __blk_end_request_cur(pd_req, 0);
+       pd_count = blk_rq_cur_sectors(pd_req);
        pd_buf = pd_req->buffer;
        spin_unlock_irqrestore(&pd_lock, saved_flags);
        return 0;
@@ -702,7 +704,7 @@ static void do_pd_request(struct request_queue * q)
 {
        if (pd_req)
                return;
-       pd_req = elv_next_request(q);
+       pd_req = blk_fetch_request(q);
        if (!pd_req)
                return;
 
index bef3b997ba3e39d11b85917b31b20f6e96a27f1c..68a90834e99388c366874be2fe4ea554e266831f 100644 (file)
@@ -750,12 +750,10 @@ static int pf_ready(void)
 
 static struct request_queue *pf_queue;
 
-static void pf_end_request(int uptodate)
+static void pf_end_request(int err)
 {
-       if (pf_req) {
-               end_request(pf_req, uptodate);
+       if (pf_req && !__blk_end_request_cur(pf_req, err))
                pf_req = NULL;
-       }
 }
 
 static void do_pf_request(struct request_queue * q)
@@ -763,17 +761,19 @@ static void do_pf_request(struct request_queue * q)
        if (pf_busy)
                return;
 repeat:
-       pf_req = elv_next_request(q);
-       if (!pf_req)
-               return;
+       if (!pf_req) {
+               pf_req = blk_fetch_request(q);
+               if (!pf_req)
+                       return;
+       }
 
        pf_current = pf_req->rq_disk->private_data;
-       pf_block = pf_req->sector;
-       pf_run = pf_req->nr_sectors;
-       pf_count = pf_req->current_nr_sectors;
+       pf_block = blk_rq_pos(pf_req);
+       pf_run = blk_rq_sectors(pf_req);
+       pf_count = blk_rq_cur_sectors(pf_req);
 
        if (pf_block + pf_count > get_capacity(pf_req->rq_disk)) {
-               pf_end_request(0);
+               pf_end_request(-EIO);
                goto repeat;
        }
 
@@ -788,7 +788,7 @@ repeat:
                pi_do_claimed(pf_current->pi, do_pf_write);
        else {
                pf_busy = 0;
-               pf_end_request(0);
+               pf_end_request(-EIO);
                goto repeat;
        }
 }
@@ -805,23 +805,22 @@ static int pf_next_buf(void)
                return 1;
        if (!pf_count) {
                spin_lock_irqsave(&pf_spin_lock, saved_flags);
-               pf_end_request(1);
-               pf_req = elv_next_request(pf_queue);
+               pf_end_request(0);
                spin_unlock_irqrestore(&pf_spin_lock, saved_flags);
                if (!pf_req)
                        return 1;
-               pf_count = pf_req->current_nr_sectors;
+               pf_count = blk_rq_cur_sectors(pf_req);
                pf_buf = pf_req->buffer;
        }
        return 0;
 }
 
-static inline void next_request(int success)
+static inline void next_request(int err)
 {
        unsigned long saved_flags;
 
        spin_lock_irqsave(&pf_spin_lock, saved_flags);
-       pf_end_request(success);
+       pf_end_request(err);
        pf_busy = 0;
        do_pf_request(pf_queue);
        spin_unlock_irqrestore(&pf_spin_lock, saved_flags);
@@ -844,7 +843,7 @@ static void do_pf_read_start(void)
                        pi_do_claimed(pf_current->pi, do_pf_read_start);
                        return;
                }
-               next_request(0);
+               next_request(-EIO);
                return;
        }
        pf_mask = STAT_DRQ;
@@ -863,7 +862,7 @@ static void do_pf_read_drq(void)
                                pi_do_claimed(pf_current->pi, do_pf_read_start);
                                return;
                        }
-                       next_request(0);
+                       next_request(-EIO);
                        return;
                }
                pi_read_block(pf_current->pi, pf_buf, 512);
@@ -871,7 +870,7 @@ static void do_pf_read_drq(void)
                        break;
        }
        pi_disconnect(pf_current->pi);
-       next_request(1);
+       next_request(0);
 }
 
 static void do_pf_write(void)
@@ -890,7 +889,7 @@ static void do_pf_write_start(void)
                        pi_do_claimed(pf_current->pi, do_pf_write_start);
                        return;
                }
-               next_request(0);
+               next_request(-EIO);
                return;
        }
 
@@ -903,7 +902,7 @@ static void do_pf_write_start(void)
                                pi_do_claimed(pf_current->pi, do_pf_write_start);
                                return;
                        }
-                       next_request(0);
+                       next_request(-EIO);
                        return;
                }
                pi_write_block(pf_current->pi, pf_buf, 512);
@@ -923,11 +922,11 @@ static void do_pf_write_done(void)
                        pi_do_claimed(pf_current->pi, do_pf_write_start);
                        return;
                }
-               next_request(0);
+               next_request(-EIO);
                return;
        }
        pi_disconnect(pf_current->pi);
-       next_request(1);
+       next_request(0);
 }
 
 static int __init pf_init(void)
index dc7a8c352da2e7c5b44a3d9a4e7a02bfd029d0c2..d57f11759480c1c2874922e773cee62ac6571472 100644 (file)
@@ -991,13 +991,15 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
  */
 static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_queue *q)
 {
-       if ((pd->settings.size << 9) / CD_FRAMESIZE <= q->max_phys_segments) {
+       if ((pd->settings.size << 9) / CD_FRAMESIZE
+           <= queue_max_phys_segments(q)) {
                /*
                 * The cdrom device can handle one segment/frame
                 */
                clear_bit(PACKET_MERGE_SEGS, &pd->flags);
                return 0;
-       } else if ((pd->settings.size << 9) / PAGE_SIZE <= q->max_phys_segments) {
+       } else if ((pd->settings.size << 9) / PAGE_SIZE
+                  <= queue_max_phys_segments(q)) {
                /*
                 * We can handle this case at the expense of some extra memory
                 * copies during write operations
@@ -2657,7 +2659,7 @@ static void pkt_init_queue(struct pktcdvd_device *pd)
        struct request_queue *q = pd->disk->queue;
 
        blk_queue_make_request(q, pkt_make_request);
-       blk_queue_hardsect_size(q, CD_FRAMESIZE);
+       blk_queue_logical_block_size(q, CD_FRAMESIZE);
        blk_queue_max_sectors(q, PACKET_MAX_SECTORS);
        blk_queue_merge_bvec(q, pkt_merge_bvec);
        q->queuedata = pd;
index bccc42bb9212d7f37086ac86160521f96bc6fea6..aaeeb544228a322efc790482f206f48afdf829a8 100644 (file)
@@ -134,13 +134,12 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
        rq_for_each_segment(bv, req, iter)
                n++;
        dev_dbg(&dev->sbd.core,
-               "%s:%u: %s req has %u bvecs for %lu sectors %lu hard sectors\n",
-               __func__, __LINE__, op, n, req->nr_sectors,
-               req->hard_nr_sectors);
+               "%s:%u: %s req has %u bvecs for %u sectors\n",
+               __func__, __LINE__, op, n, blk_rq_sectors(req));
 #endif
 
-       start_sector = req->sector * priv->blocking_factor;
-       sectors = req->nr_sectors * priv->blocking_factor;
+       start_sector = blk_rq_pos(req) * priv->blocking_factor;
+       sectors = blk_rq_sectors(req) * priv->blocking_factor;
        dev_dbg(&dev->sbd.core, "%s:%u: %s %llu sectors starting at %llu\n",
                __func__, __LINE__, op, sectors, start_sector);
 
@@ -158,7 +157,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
        if (res) {
                dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
                        __LINE__, op, res);
-               end_request(req, 0);
+               __blk_end_request_all(req, -EIO);
                return 0;
        }
 
@@ -180,7 +179,7 @@ static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
        if (res) {
                dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx\n",
                        __func__, __LINE__, res);
-               end_request(req, 0);
+               __blk_end_request_all(req, -EIO);
                return 0;
        }
 
@@ -195,7 +194,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev,
 
        dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
 
-       while ((req = elv_next_request(q))) {
+       while ((req = blk_fetch_request(q))) {
                if (blk_fs_request(req)) {
                        if (ps3disk_submit_request_sg(dev, req))
                                break;
@@ -205,7 +204,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev,
                                break;
                } else {
                        blk_dump_rq_flags(req, DEVICE_NAME " bad request");
-                       end_request(req, 0);
+                       __blk_end_request_all(req, -EIO);
                        continue;
                }
        }
@@ -231,7 +230,6 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
        struct request *req;
        int res, read, error;
        u64 tag, status;
-       unsigned long num_sectors;
        const char *op;
 
        res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
@@ -261,11 +259,9 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
        if (req->cmd_type == REQ_TYPE_LINUX_BLOCK &&
            req->cmd[0] == REQ_LB_OP_FLUSH) {
                read = 0;
-               num_sectors = req->hard_cur_sectors;
                op = "flush";
        } else {
                read = !rq_data_dir(req);
-               num_sectors = req->nr_sectors;
                op = read ? "read" : "write";
        }
        if (status) {
@@ -281,7 +277,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
        }
 
        spin_lock(&priv->lock);
-       __blk_end_request(req, error, num_sectors << 9);
+       __blk_end_request_all(req, error);
        priv->req = NULL;
        ps3disk_do_request(dev, priv->queue);
        spin_unlock(&priv->lock);
@@ -481,7 +477,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
        blk_queue_max_sectors(queue, dev->bounce_size >> 9);
        blk_queue_segment_boundary(queue, -1UL);
        blk_queue_dma_alignment(queue, dev->blk_size-1);
-       blk_queue_hardsect_size(queue, dev->blk_size);
+       blk_queue_logical_block_size(queue, dev->blk_size);
 
        blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH,
                          ps3disk_prepare_flush);
index 5861e33efe63589a2f974eee6a99172acc596bc9..cbfd9c0aef034ffd2778aaac37eec3fd4d33a61e 100644 (file)
@@ -212,11 +212,6 @@ static void vdc_end_special(struct vdc_port *port, struct vio_disk_desc *desc)
        vdc_finish(&port->vio, -err, WAITING_FOR_GEN_CMD);
 }
 
-static void vdc_end_request(struct request *req, int error, int num_sectors)
-{
-       __blk_end_request(req, error, num_sectors << 9);
-}
-
 static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr,
                        unsigned int index)
 {
@@ -239,7 +234,7 @@ static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr,
 
        rqe->req = NULL;
 
-       vdc_end_request(req, (desc->status ? -EIO : 0), desc->size >> 9);
+       __blk_end_request(req, (desc->status ? -EIO : 0), desc->size);
 
        if (blk_queue_stopped(port->disk->queue))
                blk_start_queue(port->disk->queue);
@@ -421,7 +416,7 @@ static int __send_request(struct request *req)
                desc->slice = 0;
        }
        desc->status = ~0;
-       desc->offset = (req->sector << 9) / port->vdisk_block_size;
+       desc->offset = (blk_rq_pos(req) << 9) / port->vdisk_block_size;
        desc->size = len;
        desc->ncookies = err;
 
@@ -446,14 +441,13 @@ out:
 static void do_vdc_request(struct request_queue *q)
 {
        while (1) {
-               struct request *req = elv_next_request(q);
+               struct request *req = blk_fetch_request(q);
 
                if (!req)
                        break;
 
-               blkdev_dequeue_request(req);
                if (__send_request(req) < 0)
-                       vdc_end_request(req, -EIO, req->hard_nr_sectors);
+                       __blk_end_request_all(req, -EIO);
        }
 }
 
index d22cc385693728f382bb286ae59d179816b9cc74..cf7877fb8a7d721b0ddbff0c0cced731e8c3e9fc 100644 (file)
@@ -514,7 +514,7 @@ static int floppy_read_sectors(struct floppy_state *fs,
                        ret = swim_read_sector(fs, side, track, sector,
                                                buffer);
                        if (try-- == 0)
-                               return -1;
+                               return -EIO;
                } while (ret != 512);
 
                buffer += ret;
@@ -528,45 +528,31 @@ static void redo_fd_request(struct request_queue *q)
        struct request *req;
        struct floppy_state *fs;
 
-       while ((req = elv_next_request(q))) {
+       req = blk_fetch_request(q);
+       while (req) {
+               int err = -EIO;
 
                fs = req->rq_disk->private_data;
-               if (req->sector < 0 || req->sector >= fs->total_secs) {
-                       end_request(req, 0);
-                       continue;
-               }
-               if (req->current_nr_sectors == 0) {
-                       end_request(req, 1);
-                       continue;
-               }
-               if (!fs->disk_in) {
-                       end_request(req, 0);
-                       continue;
-               }
-               if (rq_data_dir(req) == WRITE) {
-                       if (fs->write_protected) {
-                               end_request(req, 0);
-                               continue;
-                       }
-               }
+               if (blk_rq_pos(req) >= fs->total_secs)
+                       goto done;
+               if (!fs->disk_in)
+                       goto done;
+               if (rq_data_dir(req) == WRITE && fs->write_protected)
+                       goto done;
+
                switch (rq_data_dir(req)) {
                case WRITE:
                        /* NOT IMPLEMENTED */
-                       end_request(req, 0);
                        break;
                case READ:
-                       if (floppy_read_sectors(fs, req->sector,
-                                               req->current_nr_sectors,
-                                               req->buffer)) {
-                               end_request(req, 0);
-                               continue;
-                       }
-                       req->nr_sectors -= req->current_nr_sectors;
-                       req->sector += req->current_nr_sectors;
-                       req->buffer += req->current_nr_sectors * 512;
-                       end_request(req, 1);
+                       err = floppy_read_sectors(fs, blk_rq_pos(req),
+                                                 blk_rq_cur_sectors(req),
+                                                 req->buffer);
                        break;
                }
+       done:
+               if (!__blk_end_request_cur(req, err))
+                       req = blk_fetch_request(q);
        }
 }
 
index 612965307ba009e04c8f733a870a5b4df69b4572..80df93e3cdd05f0d9c219b6d18bbf8b7a6de517d 100644 (file)
@@ -251,6 +251,20 @@ static int floppy_release(struct gendisk *disk, fmode_t mode);
 static int floppy_check_change(struct gendisk *disk);
 static int floppy_revalidate(struct gendisk *disk);
 
+static bool swim3_end_request(int err, unsigned int nr_bytes)
+{
+       if (__blk_end_request(fd_req, err, nr_bytes))
+               return true;
+
+       fd_req = NULL;
+       return false;
+}
+
+static bool swim3_end_request_cur(int err)
+{
+       return swim3_end_request(err, blk_rq_cur_bytes(fd_req));
+}
+
 static void swim3_select(struct floppy_state *fs, int sel)
 {
        struct swim3 __iomem *sw = fs->swim3;
@@ -310,25 +324,27 @@ static void start_request(struct floppy_state *fs)
                wake_up(&fs->wait);
                return;
        }
-       while (fs->state == idle && (req = elv_next_request(swim3_queue))) {
+       while (fs->state == idle) {
+               if (!fd_req) {
+                       fd_req = blk_fetch_request(swim3_queue);
+                       if (!fd_req)
+                               break;
+               }
+               req = fd_req;
 #if 0
-               printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n",
+               printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n",
                       req->rq_disk->disk_name, req->cmd,
-                      (long)req->sector, req->nr_sectors, req->buffer);
-               printk("           errors=%d current_nr_sectors=%ld\n",
-                      req->errors, req->current_nr_sectors);
+                      (long)blk_rq_pos(req), blk_rq_sectors(req), req->buffer);
+               printk("           errors=%d current_nr_sectors=%u\n",
+                      req->errors, blk_rq_cur_sectors(req));
 #endif
 
-               if (req->sector < 0 || req->sector >= fs->total_secs) {
-                       end_request(req, 0);
-                       continue;
-               }
-               if (req->current_nr_sectors == 0) {
-                       end_request(req, 1);
+               if (blk_rq_pos(req) >= fs->total_secs) {
+                       swim3_end_request_cur(-EIO);
                        continue;
                }
                if (fs->ejected) {
-                       end_request(req, 0);
+                       swim3_end_request_cur(-EIO);
                        continue;
                }
 
@@ -336,18 +352,19 @@ static void start_request(struct floppy_state *fs)
                        if (fs->write_prot < 0)
                                fs->write_prot = swim3_readbit(fs, WRITE_PROT);
                        if (fs->write_prot) {
-                               end_request(req, 0);
+                               swim3_end_request_cur(-EIO);
                                continue;
                        }
                }
 
-               /* Do not remove the cast. req->sector is now a sector_t and
-                * can be 64 bits, but it will never go past 32 bits for this
-                * driver anyway, so we can safely cast it down and not have
-                * to do a 64/32 division
+               /* Do not remove the cast. blk_rq_pos(req) is now a
+                * sector_t and can be 64 bits, but it will never go
+                * past 32 bits for this driver anyway, so we can
+                * safely cast it down and not have to do a 64/32
+                * division
                 */
-               fs->req_cyl = ((long)req->sector) / fs->secpercyl;
-               x = ((long)req->sector) % fs->secpercyl;
+               fs->req_cyl = ((long)blk_rq_pos(req)) / fs->secpercyl;
+               x = ((long)blk_rq_pos(req)) % fs->secpercyl;
                fs->head = x / fs->secpertrack;
                fs->req_sector = x % fs->secpertrack + 1;
                fd_req = req;
@@ -424,7 +441,7 @@ static inline void setup_transfer(struct floppy_state *fs)
        struct dbdma_cmd *cp = fs->dma_cmd;
        struct dbdma_regs __iomem *dr = fs->dma;
 
-       if (fd_req->current_nr_sectors <= 0) {
+       if (blk_rq_cur_sectors(fd_req) <= 0) {
                printk(KERN_ERR "swim3: transfer 0 sectors?\n");
                return;
        }
@@ -432,8 +449,8 @@ static inline void setup_transfer(struct floppy_state *fs)
                n = 1;
        else {
                n = fs->secpertrack - fs->req_sector + 1;
-               if (n > fd_req->current_nr_sectors)
-                       n = fd_req->current_nr_sectors;
+               if (n > blk_rq_cur_sectors(fd_req))
+                       n = blk_rq_cur_sectors(fd_req);
        }
        fs->scount = n;
        swim3_select(fs, fs->head? READ_DATA_1: READ_DATA_0);
@@ -508,7 +525,7 @@ static void act(struct floppy_state *fs)
                case do_transfer:
                        if (fs->cur_cyl != fs->req_cyl) {
                                if (fs->retries > 5) {
-                                       end_request(fd_req, 0);
+                                       swim3_end_request_cur(-EIO);
                                        fs->state = idle;
                                        return;
                                }
@@ -540,7 +557,7 @@ static void scan_timeout(unsigned long data)
        out_8(&sw->intr_enable, 0);
        fs->cur_cyl = -1;
        if (fs->retries > 5) {
-               end_request(fd_req, 0);
+               swim3_end_request_cur(-EIO);
                fs->state = idle;
                start_request(fs);
        } else {
@@ -559,7 +576,7 @@ static void seek_timeout(unsigned long data)
        out_8(&sw->select, RELAX);
        out_8(&sw->intr_enable, 0);
        printk(KERN_ERR "swim3: seek timeout\n");
-       end_request(fd_req, 0);
+       swim3_end_request_cur(-EIO);
        fs->state = idle;
        start_request(fs);
 }
@@ -583,7 +600,7 @@ static void settle_timeout(unsigned long data)
                return;
        }
        printk(KERN_ERR "swim3: seek settle timeout\n");
-       end_request(fd_req, 0);
+       swim3_end_request_cur(-EIO);
        fs->state = idle;
        start_request(fs);
 }
@@ -593,8 +610,6 @@ static void xfer_timeout(unsigned long data)
        struct floppy_state *fs = (struct floppy_state *) data;
        struct swim3 __iomem *sw = fs->swim3;
        struct dbdma_regs __iomem *dr = fs->dma;
-       struct dbdma_cmd *cp = fs->dma_cmd;
-       unsigned long s;
        int n;
 
        fs->timeout_pending = 0;
@@ -605,17 +620,10 @@ static void xfer_timeout(unsigned long data)
        out_8(&sw->intr_enable, 0);
        out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION);
        out_8(&sw->select, RELAX);
-       if (rq_data_dir(fd_req) == WRITE)
-               ++cp;
-       if (ld_le16(&cp->xfer_status) != 0)
-               s = fs->scount - ((ld_le16(&cp->res_count) + 511) >> 9);
-       else
-               s = 0;
-       fd_req->sector += s;
-       fd_req->current_nr_sectors -= s;
        printk(KERN_ERR "swim3: timeout %sing sector %ld\n",
-              (rq_data_dir(fd_req)==WRITE? "writ": "read"), (long)fd_req->sector);
-       end_request(fd_req, 0);
+              (rq_data_dir(fd_req)==WRITE? "writ": "read"),
+              (long)blk_rq_pos(fd_req));
+       swim3_end_request_cur(-EIO);
        fs->state = idle;
        start_request(fs);
 }
@@ -646,7 +654,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id)
                                printk(KERN_ERR "swim3: seen sector but cyl=ff?\n");
                                fs->cur_cyl = -1;
                                if (fs->retries > 5) {
-                                       end_request(fd_req, 0);
+                                       swim3_end_request_cur(-EIO);
                                        fs->state = idle;
                                        start_request(fs);
                                } else {
@@ -719,9 +727,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id)
                if (intr & ERROR_INTR) {
                        n = fs->scount - 1 - resid / 512;
                        if (n > 0) {
-                               fd_req->sector += n;
-                               fd_req->current_nr_sectors -= n;
-                               fd_req->buffer += n * 512;
+                               blk_update_request(fd_req, 0, n << 9);
                                fs->req_sector += n;
                        }
                        if (fs->retries < 5) {
@@ -730,8 +736,8 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id)
                        } else {
                                printk("swim3: error %sing block %ld (err=%x)\n",
                                       rq_data_dir(fd_req) == WRITE? "writ": "read",
-                                      (long)fd_req->sector, err);
-                               end_request(fd_req, 0);
+                                      (long)blk_rq_pos(fd_req), err);
+                               swim3_end_request_cur(-EIO);
                                fs->state = idle;
                        }
                } else {
@@ -740,18 +746,12 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id)
                                printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid);
                                printk(KERN_ERR "  state=%d, dir=%x, intr=%x, err=%x\n",
                                       fs->state, rq_data_dir(fd_req), intr, err);
-                               end_request(fd_req, 0);
+                               swim3_end_request_cur(-EIO);
                                fs->state = idle;
                                start_request(fs);
                                break;
                        }
-                       fd_req->sector += fs->scount;
-                       fd_req->current_nr_sectors -= fs->scount;
-                       fd_req->buffer += fs->scount * 512;
-                       if (fd_req->current_nr_sectors <= 0) {
-                               end_request(fd_req, 1);
-                               fs->state = idle;
-                       } else {
+                       if (swim3_end_request(0, fs->scount << 9)) {
                                fs->req_sector += fs->scount;
                                if (fs->req_sector > fs->secpertrack) {
                                        fs->req_sector -= fs->secpertrack;
@@ -761,7 +761,8 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id)
                                        }
                                }
                                act(fs);
-                       }
+                       } else
+                               fs->state = idle;
                }
                if (fs->state == idle)
                        start_request(fs);
index ff0448e4bf036d36fc6e2a2a071be0ff13b19f99..da403b6a7f434525a694fb139d58950d65769586 100644 (file)
@@ -749,8 +749,7 @@ static inline void carm_end_request_queued(struct carm_host *host,
        struct request *req = crq->rq;
        int rc;
 
-       rc = __blk_end_request(req, error, blk_rq_bytes(req));
-       assert(rc == 0);
+       __blk_end_request_all(req, error);
 
        rc = carm_put_request(host, crq);
        assert(rc == 0);
@@ -811,12 +810,10 @@ static void carm_oob_rq_fn(struct request_queue *q)
 
        while (1) {
                DPRINTK("get req\n");
-               rq = elv_next_request(q);
+               rq = blk_fetch_request(q);
                if (!rq)
                        break;
 
-               blkdev_dequeue_request(rq);
-
                crq = rq->special;
                assert(crq != NULL);
                assert(crq->rq == rq);
@@ -847,7 +844,7 @@ static void carm_rq_fn(struct request_queue *q)
 
 queue_one_request:
        VPRINTK("get req\n");
-       rq = elv_next_request(q);
+       rq = blk_peek_request(q);
        if (!rq)
                return;
 
@@ -858,7 +855,7 @@ queue_one_request:
        }
        crq->rq = rq;
 
-       blkdev_dequeue_request(rq);
+       blk_start_request(rq);
 
        if (rq_data_dir(rq) == WRITE) {
                writing = 1;
@@ -904,10 +901,10 @@ queue_one_request:
        msg->sg_count   = n_elem;
        msg->sg_type    = SGT_32BIT;
        msg->handle     = cpu_to_le32(TAG_ENCODE(crq->tag));
-       msg->lba        = cpu_to_le32(rq->sector & 0xffffffff);
-       tmp             = (rq->sector >> 16) >> 16;
+       msg->lba        = cpu_to_le32(blk_rq_pos(rq) & 0xffffffff);
+       tmp             = (blk_rq_pos(rq) >> 16) >> 16;
        msg->lba_high   = cpu_to_le16( (u16) tmp );
-       msg->lba_count  = cpu_to_le16(rq->nr_sectors);
+       msg->lba_count  = cpu_to_le16(blk_rq_sectors(rq));
 
        msg_size = sizeof(struct carm_msg_rw) - sizeof(msg->sg);
        for (i = 0; i < n_elem; i++) {
index 689cd27ac890afff8c39dc11bdac5e605e37816c..cc54473b8e77fa857d37eff69a053ff16b20c89c 100644 (file)
@@ -360,8 +360,7 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
 static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
     struct ub_scsi_cmd *cmd, struct ub_request *urq);
 static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_end_rq(struct request *rq, unsigned int status,
-    unsigned int cmd_len);
+static void ub_end_rq(struct request *rq, unsigned int status);
 static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
     struct ub_request *urq, struct ub_scsi_cmd *cmd);
 static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
@@ -627,7 +626,7 @@ static void ub_request_fn(struct request_queue *q)
        struct ub_lun *lun = q->queuedata;
        struct request *rq;
 
-       while ((rq = elv_next_request(q)) != NULL) {
+       while ((rq = blk_peek_request(q)) != NULL) {
                if (ub_request_fn_1(lun, rq) != 0) {
                        blk_stop_queue(q);
                        break;
@@ -643,14 +642,14 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
        int n_elem;
 
        if (atomic_read(&sc->poison)) {
-               blkdev_dequeue_request(rq);
-               ub_end_rq(rq, DID_NO_CONNECT << 16, blk_rq_bytes(rq));
+               blk_start_request(rq);
+               ub_end_rq(rq, DID_NO_CONNECT << 16);
                return 0;
        }
 
        if (lun->changed && !blk_pc_request(rq)) {
-               blkdev_dequeue_request(rq);
-               ub_end_rq(rq, SAM_STAT_CHECK_CONDITION, blk_rq_bytes(rq));
+               blk_start_request(rq);
+               ub_end_rq(rq, SAM_STAT_CHECK_CONDITION);
                return 0;
        }
 
@@ -660,7 +659,7 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
                return -1;
        memset(cmd, 0, sizeof(struct ub_scsi_cmd));
 
-       blkdev_dequeue_request(rq);
+       blk_start_request(rq);
 
        urq = &lun->urq;
        memset(urq, 0, sizeof(struct ub_request));
@@ -702,7 +701,7 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
 
 drop:
        ub_put_cmd(lun, cmd);
-       ub_end_rq(rq, DID_ERROR << 16, blk_rq_bytes(rq));
+       ub_end_rq(rq, DID_ERROR << 16);
        return 0;
 }
 
@@ -723,11 +722,11 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
        /*
         * build the command
         *
-        * The call to blk_queue_hardsect_size() guarantees that request
+        * The call to blk_queue_logical_block_size() guarantees that request
         * is aligned, but it is given in terms of 512 byte units, always.
         */
-       block = rq->sector >> lun->capacity.bshift;
-       nblks = rq->nr_sectors >> lun->capacity.bshift;
+       block = blk_rq_pos(rq) >> lun->capacity.bshift;
+       nblks = blk_rq_sectors(rq) >> lun->capacity.bshift;
 
        cmd->cdb[0] = (cmd->dir == UB_DIR_READ)? READ_10: WRITE_10;
        /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */
@@ -739,7 +738,7 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
        cmd->cdb[8] = nblks;
        cmd->cdb_len = 10;
 
-       cmd->len = rq->nr_sectors * 512;
+       cmd->len = blk_rq_bytes(rq);
 }
 
 static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
@@ -747,7 +746,7 @@ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
 {
        struct request *rq = urq->rq;
 
-       if (rq->data_len == 0) {
+       if (blk_rq_bytes(rq) == 0) {
                cmd->dir = UB_DIR_NONE;
        } else {
                if (rq_data_dir(rq) == WRITE)
@@ -762,7 +761,7 @@ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
        memcpy(&cmd->cdb, rq->cmd, rq->cmd_len);
        cmd->cdb_len = rq->cmd_len;
 
-       cmd->len = rq->data_len;
+       cmd->len = blk_rq_bytes(rq);
 
        /*
         * To reapply this to every URB is not as incorrect as it looks.
@@ -777,16 +776,15 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        struct ub_request *urq = cmd->back;
        struct request *rq;
        unsigned int scsi_status;
-       unsigned int cmd_len;
 
        rq = urq->rq;
 
        if (cmd->error == 0) {
                if (blk_pc_request(rq)) {
-                       if (cmd->act_len >= rq->data_len)
-                               rq->data_len = 0;
+                       if (cmd->act_len >= rq->resid_len)
+                               rq->resid_len = 0;
                        else
-                               rq->data_len -= cmd->act_len;
+                               rq->resid_len -= cmd->act_len;
                        scsi_status = 0;
                } else {
                        if (cmd->act_len != cmd->len) {
@@ -818,17 +816,14 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 
        urq->rq = NULL;
 
-       cmd_len = cmd->len;
        ub_put_cmd(lun, cmd);
-       ub_end_rq(rq, scsi_status, cmd_len);
+       ub_end_rq(rq, scsi_status);
        blk_start_queue(lun->disk->queue);
 }
 
-static void ub_end_rq(struct request *rq, unsigned int scsi_status,
-    unsigned int cmd_len)
+static void ub_end_rq(struct request *rq, unsigned int scsi_status)
 {
        int error;
-       long rqlen;
 
        if (scsi_status == 0) {
                error = 0;
@@ -836,12 +831,7 @@ static void ub_end_rq(struct request *rq, unsigned int scsi_status,
                error = -EIO;
                rq->errors = scsi_status;
        }
-       rqlen = blk_rq_bytes(rq);    /* Oddly enough, this is the residue. */
-       if (__blk_end_request(rq, error, cmd_len)) {
-               printk(KERN_WARNING DRV_NAME
-                   ": __blk_end_request blew, %s-cmd total %u rqlen %ld\n",
-                   blk_pc_request(rq)? "pc": "fs", cmd_len, rqlen);
-       }
+       __blk_end_request_all(rq, error);
 }
 
 static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
@@ -1759,7 +1749,7 @@ static int ub_bd_revalidate(struct gendisk *disk)
        ub_revalidate(lun->udev, lun);
 
        /* XXX Support sector size switching like in sr.c */
-       blk_queue_hardsect_size(disk->queue, lun->capacity.bsize);
+       blk_queue_logical_block_size(disk->queue, lun->capacity.bsize);
        set_capacity(disk, lun->capacity.nsec);
        // set_disk_ro(sdkp->disk, lun->readonly);
 
@@ -2334,7 +2324,7 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
        blk_queue_max_phys_segments(q, UB_MAX_REQ_SG);
        blk_queue_segment_boundary(q, 0xffffffff);      /* Dubious. */
        blk_queue_max_sectors(q, UB_MAX_SECTORS);
-       blk_queue_hardsect_size(q, lun->capacity.bsize);
+       blk_queue_logical_block_size(q, lun->capacity.bsize);
 
        lun->disk = disk;
        q->queuedata = lun;
index ecccf65dce2f07a7a41a12cdfcbab7633da409c5..390d69bb7c482ad1a79a09a42192575b692b4980 100644 (file)
@@ -252,7 +252,7 @@ static int send_request(struct request *req)
        struct viodasd_device *d;
        unsigned long flags;
 
-       start = (u64)req->sector << 9;
+       start = (u64)blk_rq_pos(req) << 9;
 
        if (rq_data_dir(req) == READ) {
                direction = DMA_FROM_DEVICE;
@@ -361,19 +361,17 @@ static void do_viodasd_request(struct request_queue *q)
         * back later.
         */
        while (num_req_outstanding < VIOMAXREQ) {
-               req = elv_next_request(q);
+               req = blk_fetch_request(q);
                if (req == NULL)
                        return;
-               /* dequeue the current request from the queue */
-               blkdev_dequeue_request(req);
                /* check that request contains a valid command */
                if (!blk_fs_request(req)) {
-                       viodasd_end_request(req, -EIO, req->hard_nr_sectors);
+                       viodasd_end_request(req, -EIO, blk_rq_sectors(req));
                        continue;
                }
                /* Try sending the request */
                if (send_request(req) != 0)
-                       viodasd_end_request(req, -EIO, req->hard_nr_sectors);
+                       viodasd_end_request(req, -EIO, blk_rq_sectors(req));
        }
 }
 
@@ -590,7 +588,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
                err = vio_lookup_rc(viodasd_err_table, bevent->sub_result);
                printk(VIOD_KERN_WARNING "read/write error %d:0x%04x (%s)\n",
                                event->xRc, bevent->sub_result, err->msg);
-               num_sect = req->hard_nr_sectors;
+               num_sect = blk_rq_sectors(req);
        }
        qlock = req->q->queue_lock;
        spin_lock_irqsave(qlock, irq_flags);
index 5d34764c8a8726d5103e6e723eaae6ab28a6a422..c0facaa55cf46ee96932d08ee453829735bdf939 100644 (file)
@@ -37,6 +37,7 @@ struct virtblk_req
        struct list_head list;
        struct request *req;
        struct virtio_blk_outhdr out_hdr;
+       struct virtio_scsi_inhdr in_hdr;
        u8 status;
 };
 
@@ -50,6 +51,7 @@ static void blk_done(struct virtqueue *vq)
        spin_lock_irqsave(&vblk->lock, flags);
        while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) {
                int error;
+
                switch (vbr->status) {
                case VIRTIO_BLK_S_OK:
                        error = 0;
@@ -62,7 +64,13 @@ static void blk_done(struct virtqueue *vq)
                        break;
                }
 
-               __blk_end_request(vbr->req, error, blk_rq_bytes(vbr->req));
+               if (blk_pc_request(vbr->req)) {
+                       vbr->req->resid_len = vbr->in_hdr.residual;
+                       vbr->req->sense_len = vbr->in_hdr.sense_len;
+                       vbr->req->errors = vbr->in_hdr.errors;
+               }
+
+               __blk_end_request_all(vbr->req, error);
                list_del(&vbr->list);
                mempool_free(vbr, vblk->pool);
        }
@@ -74,7 +82,7 @@ static void blk_done(struct virtqueue *vq)
 static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
                   struct request *req)
 {
-       unsigned long num, out, in;
+       unsigned long num, out = 0, in = 0;
        struct virtblk_req *vbr;
 
        vbr = mempool_alloc(vblk->pool, GFP_ATOMIC);
@@ -85,7 +93,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
        vbr->req = req;
        if (blk_fs_request(vbr->req)) {
                vbr->out_hdr.type = 0;
-               vbr->out_hdr.sector = vbr->req->sector;
+               vbr->out_hdr.sector = blk_rq_pos(vbr->req);
                vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
        } else if (blk_pc_request(vbr->req)) {
                vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD;
@@ -99,18 +107,36 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
        if (blk_barrier_rq(vbr->req))
                vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER;
 
-       sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr));
-       num = blk_rq_map_sg(q, vbr->req, vblk->sg+1);
-       sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status));
+       sg_set_buf(&vblk->sg[out++], &vbr->out_hdr, sizeof(vbr->out_hdr));
 
-       if (rq_data_dir(vbr->req) == WRITE) {
-               vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
-               out = 1 + num;
-               in = 1;
-       } else {
-               vbr->out_hdr.type |= VIRTIO_BLK_T_IN;
-               out = 1;
-               in = 1 + num;
+       /*
+        * If this is a packet command we need a couple of additional headers.
+        * Behind the normal outhdr we put a segment with the scsi command
+        * block, and before the normal inhdr we put the sense data and the
+        * inhdr with additional status information before the normal inhdr.
+        */
+       if (blk_pc_request(vbr->req))
+               sg_set_buf(&vblk->sg[out++], vbr->req->cmd, vbr->req->cmd_len);
+
+       num = blk_rq_map_sg(q, vbr->req, vblk->sg + out);
+
+       if (blk_pc_request(vbr->req)) {
+               sg_set_buf(&vblk->sg[num + out + in++], vbr->req->sense, 96);
+               sg_set_buf(&vblk->sg[num + out + in++], &vbr->in_hdr,
+                          sizeof(vbr->in_hdr));
+       }
+
+       sg_set_buf(&vblk->sg[num + out + in++], &vbr->status,
+                  sizeof(vbr->status));
+
+       if (num) {
+               if (rq_data_dir(vbr->req) == WRITE) {
+                       vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
+                       out += num;
+               } else {
+                       vbr->out_hdr.type |= VIRTIO_BLK_T_IN;
+                       in += num;
+               }
        }
 
        if (vblk->vq->vq_ops->add_buf(vblk->vq, vblk->sg, out, in, vbr)) {
@@ -124,12 +150,11 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
 
 static void do_virtblk_request(struct request_queue *q)
 {
-       struct virtio_blk *vblk = NULL;
+       struct virtio_blk *vblk = q->queuedata;
        struct request *req;
        unsigned int issued = 0;
 
-       while ((req = elv_next_request(q)) != NULL) {
-               vblk = req->rq_disk->private_data;
+       while ((req = blk_peek_request(q)) != NULL) {
                BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);
 
                /* If this request fails, stop queue and wait for something to
@@ -138,7 +163,7 @@ static void do_virtblk_request(struct request_queue *q)
                        blk_stop_queue(q);
                        break;
                }
-               blkdev_dequeue_request(req);
+               blk_start_request(req);
                issued++;
        }
 
@@ -146,12 +171,51 @@ static void do_virtblk_request(struct request_queue *q)
                vblk->vq->vq_ops->kick(vblk->vq);
 }
 
+/* return ATA identify data
+ */
+static int virtblk_identify(struct gendisk *disk, void *argp)
+{
+       struct virtio_blk *vblk = disk->private_data;
+       void *opaque;
+       int err = -ENOMEM;
+
+       opaque = kmalloc(VIRTIO_BLK_ID_BYTES, GFP_KERNEL);
+       if (!opaque)
+               goto out;
+
+       err = virtio_config_buf(vblk->vdev, VIRTIO_BLK_F_IDENTIFY,
+               offsetof(struct virtio_blk_config, identify), opaque,
+               VIRTIO_BLK_ID_BYTES);
+
+       if (err)
+               goto out_kfree;
+
+       if (copy_to_user(argp, opaque, VIRTIO_BLK_ID_BYTES))
+               err = -EFAULT;
+
+out_kfree:
+       kfree(opaque);
+out:
+       return err;
+}
+
 static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
                         unsigned cmd, unsigned long data)
 {
-       return scsi_cmd_ioctl(bdev->bd_disk->queue,
-                             bdev->bd_disk, mode, cmd,
-                             (void __user *)data);
+       struct gendisk *disk = bdev->bd_disk;
+       struct virtio_blk *vblk = disk->private_data;
+       void __user *argp = (void __user *)data;
+
+       if (cmd == HDIO_GET_IDENTITY)
+               return virtblk_identify(disk, argp);
+
+       /*
+        * Only allow the generic SCSI ioctls if the host can support it.
+        */
+       if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI))
+               return -ENOIOCTLCMD;
+
+       return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp);
 }
 
 /* We provide getgeo only to please some old bootloader/partitioning tools */
@@ -249,6 +313,7 @@ static int virtblk_probe(struct virtio_device *vdev)
                goto out_put_disk;
        }
 
+       vblk->disk->queue->queuedata = vblk;
        queue_flag_set_unlocked(QUEUE_FLAG_VIRT, vblk->disk->queue);
 
        if (index < 26) {
@@ -313,7 +378,7 @@ static int virtblk_probe(struct virtio_device *vdev)
                                offsetof(struct virtio_blk_config, blk_size),
                                &blk_size);
        if (!err)
-               blk_queue_hardsect_size(vblk->disk->queue, blk_size);
+               blk_queue_logical_block_size(vblk->disk->queue, blk_size);
 
        add_disk(vblk->disk);
        return 0;
@@ -356,6 +421,7 @@ static struct virtio_device_id id_table[] = {
 static unsigned int features[] = {
        VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
        VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
+       VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_IDENTIFY
 };
 
 static struct virtio_driver virtio_blk = {
index 64b496fce98bb2a19fd17eb22ef5a192f67ae7bb..ce2429219925597edddb597ed88c09ff37c48b75 100644 (file)
@@ -305,30 +305,25 @@ static void do_xd_request (struct request_queue * q)
        if (xdc_busy)
                return;
 
-       while ((req = elv_next_request(q)) != NULL) {
-               unsigned block = req->sector;
-               unsigned count = req->nr_sectors;
-               int rw = rq_data_dir(req);
+       req = blk_fetch_request(q);
+       while (req) {
+               unsigned block = blk_rq_pos(req);
+               unsigned count = blk_rq_cur_sectors(req);
                XD_INFO *disk = req->rq_disk->private_data;
-               int res = 0;
+               int res = -EIO;
                int retry;
 
-               if (!blk_fs_request(req)) {
-                       end_request(req, 0);
-                       continue;
-               }
-               if (block + count > get_capacity(req->rq_disk)) {
-                       end_request(req, 0);
-                       continue;
-               }
-               if (rw != READ && rw != WRITE) {
-                       printk("do_xd_request: unknown request\n");
-                       end_request(req, 0);
-                       continue;
-               }
+               if (!blk_fs_request(req))
+                       goto done;
+               if (block + count > get_capacity(req->rq_disk))
+                       goto done;
                for (retry = 0; (retry < XD_RETRIES) && !res; retry++)
-                       res = xd_readwrite(rw, disk, req->buffer, block, count);
-               end_request(req, res);  /* wrap up, 0 = fail, 1 = success */
+                       res = xd_readwrite(rq_data_dir(req), disk, req->buffer,
+                                          block, count);
+       done:
+               /* wrap up, 0 = success, -errno = fail */
+               if (!__blk_end_request_cur(req, res))
+                       req = blk_fetch_request(q);
        }
 }
 
@@ -418,7 +413,7 @@ static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_
                                printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write"));
                                xd_recalibrate(drive);
                                spin_lock_irq(&xd_lock);
-                               return (0);
+                               return -EIO;
                        case 2:
                                if (sense[0] & 0x30) {
                                        printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing"));
@@ -439,7 +434,7 @@ static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_
                                else
                                        printk(" - no valid disk address\n");
                                spin_lock_irq(&xd_lock);
-                               return (0);
+                               return -EIO;
                }
                if (xd_dma_buffer)
                        for (i=0; i < (temp * 0x200); i++)
@@ -448,7 +443,7 @@ static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_
                count -= temp, buffer += temp * 0x200, block += temp;
        }
        spin_lock_irq(&xd_lock);
-       return (1);
+       return 0;
 }
 
 /* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
index a6cbf7b808e62c15a813c0bd18a78e5f45662eb3..c1996829d5ecb92231042afd0cdc90ee7b4ad186 100644 (file)
@@ -122,7 +122,7 @@ static DEFINE_SPINLOCK(blkif_io_lock);
 static int get_id_from_freelist(struct blkfront_info *info)
 {
        unsigned long free = info->shadow_free;
-       BUG_ON(free > BLK_RING_SIZE);
+       BUG_ON(free >= BLK_RING_SIZE);
        info->shadow_free = info->shadow[free].req.id;
        info->shadow[free].req.id = 0x0fffffee; /* debug */
        return free;
@@ -231,7 +231,7 @@ static int blkif_queue_request(struct request *req)
        info->shadow[id].request = (unsigned long)req;
 
        ring_req->id = id;
-       ring_req->sector_number = (blkif_sector_t)req->sector;
+       ring_req->sector_number = (blkif_sector_t)blk_rq_pos(req);
        ring_req->handle = info->handle;
 
        ring_req->operation = rq_data_dir(req) ?
@@ -299,25 +299,25 @@ static void do_blkif_request(struct request_queue *rq)
 
        queued = 0;
 
-       while ((req = elv_next_request(rq)) != NULL) {
+       while ((req = blk_peek_request(rq)) != NULL) {
                info = req->rq_disk->private_data;
-               if (!blk_fs_request(req)) {
-                       end_request(req, 0);
-                       continue;
-               }
 
                if (RING_FULL(&info->ring))
                        goto wait;
 
-               pr_debug("do_blk_req %p: cmd %p, sec %lx, "
-                        "(%u/%li) buffer:%p [%s]\n",
-                        req, req->cmd, (unsigned long)req->sector,
-                        req->current_nr_sectors,
-                        req->nr_sectors, req->buffer,
-                        rq_data_dir(req) ? "write" : "read");
+               blk_start_request(req);
 
+               if (!blk_fs_request(req)) {
+                       __blk_end_request_all(req, -EIO);
+                       continue;
+               }
+
+               pr_debug("do_blk_req %p: cmd %p, sec %lx, "
+                        "(%u/%u) buffer:%p [%s]\n",
+                        req, req->cmd, (unsigned long)blk_rq_pos(req),
+                        blk_rq_cur_sectors(req), blk_rq_sectors(req),
+                        req->buffer, rq_data_dir(req) ? "write" : "read");
 
-               blkdev_dequeue_request(req);
                if (blkif_queue_request(req)) {
                        blk_requeue_request(rq, req);
 wait:
@@ -344,7 +344,7 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
        queue_flag_set_unlocked(QUEUE_FLAG_VIRT, rq);
 
        /* Hard sector size and max sectors impersonate the equiv. hardware. */
-       blk_queue_hardsect_size(rq, sector_size);
+       blk_queue_logical_block_size(rq, sector_size);
        blk_queue_max_sectors(rq, 512);
 
        /* Each segment in a request is up to an aligned page in size. */
@@ -551,7 +551,6 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
 
        for (i = info->ring.rsp_cons; i != rp; i++) {
                unsigned long id;
-               int ret;
 
                bret = RING_GET_RESPONSE(&info->ring, i);
                id   = bret->id;
@@ -578,8 +577,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
                                dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
                                        "request: %x\n", bret->status);
 
-                       ret = __blk_end_request(req, error, blk_rq_bytes(req));
-                       BUG_ON(ret);
+                       __blk_end_request_all(req, error);
                        break;
                default:
                        BUG();
index 4aecf5dc6a93fe546bd80f3a2eba31b84d674567..f08491a3a813b84e83df249196636c8829466cf7 100644 (file)
@@ -463,10 +463,11 @@ struct request *ace_get_next_request(struct request_queue * q)
 {
        struct request *req;
 
-       while ((req = elv_next_request(q)) != NULL) {
+       while ((req = blk_peek_request(q)) != NULL) {
                if (blk_fs_request(req))
                        break;
-               end_request(req, 0);
+               blk_start_request(req);
+               __blk_end_request_all(req, -EIO);
        }
        return req;
 }
@@ -492,9 +493,13 @@ static void ace_fsm_dostate(struct ace_device *ace)
                set_capacity(ace->gd, 0);
                dev_info(ace->dev, "No CF in slot\n");
 
-               /* Drop all pending requests */
-               while ((req = elv_next_request(ace->queue)) != NULL)
-                       end_request(req, 0);
+               /* Drop all in-flight and pending requests */
+               if (ace->req) {
+                       __blk_end_request_all(ace->req, -EIO);
+                       ace->req = NULL;
+               }
+               while ((req = blk_fetch_request(ace->queue)) != NULL)
+                       __blk_end_request_all(req, -EIO);
 
                /* Drop back to IDLE state and notify waiters */
                ace->fsm_state = ACE_FSM_STATE_IDLE;
@@ -642,19 +647,21 @@ static void ace_fsm_dostate(struct ace_device *ace)
                        ace->fsm_state = ACE_FSM_STATE_IDLE;
                        break;
                }
+               blk_start_request(req);
 
                /* Okay, it's a data request, set it up for transfer */
                dev_dbg(ace->dev,
-                       "request: sec=%llx hcnt=%lx, ccnt=%x, dir=%i\n",
-                       (unsigned long long) req->sector, req->hard_nr_sectors,
-                       req->current_nr_sectors, rq_data_dir(req));
+                       "request: sec=%llx hcnt=%x, ccnt=%x, dir=%i\n",
+                       (unsigned long long)blk_rq_pos(req),
+                       blk_rq_sectors(req), blk_rq_cur_sectors(req),
+                       rq_data_dir(req));
 
                ace->req = req;
                ace->data_ptr = req->buffer;
-               ace->data_count = req->current_nr_sectors * ACE_BUF_PER_SECTOR;
-               ace_out32(ace, ACE_MPULBA, req->sector & 0x0FFFFFFF);
+               ace->data_count = blk_rq_cur_sectors(req) * ACE_BUF_PER_SECTOR;
+               ace_out32(ace, ACE_MPULBA, blk_rq_pos(req) & 0x0FFFFFFF);
 
-               count = req->hard_nr_sectors;
+               count = blk_rq_sectors(req);
                if (rq_data_dir(req)) {
                        /* Kick off write request */
                        dev_dbg(ace->dev, "write data\n");
@@ -688,7 +695,7 @@ static void ace_fsm_dostate(struct ace_device *ace)
                        dev_dbg(ace->dev,
                                "CFBSY set; t=%i iter=%i c=%i dc=%i irq=%i\n",
                                ace->fsm_task, ace->fsm_iter_num,
-                               ace->req->current_nr_sectors * 16,
+                               blk_rq_cur_sectors(ace->req) * 16,
                                ace->data_count, ace->in_irq);
                        ace_fsm_yield(ace);     /* need to poll CFBSY bit */
                        break;
@@ -697,7 +704,7 @@ static void ace_fsm_dostate(struct ace_device *ace)
                        dev_dbg(ace->dev,
                                "DATABUF not set; t=%i iter=%i c=%i dc=%i irq=%i\n",
                                ace->fsm_task, ace->fsm_iter_num,
-                               ace->req->current_nr_sectors * 16,
+                               blk_rq_cur_sectors(ace->req) * 16,
                                ace->data_count, ace->in_irq);
                        ace_fsm_yieldirq(ace);
                        break;
@@ -717,14 +724,13 @@ static void ace_fsm_dostate(struct ace_device *ace)
                }
 
                /* bio finished; is there another one? */
-               if (__blk_end_request(ace->req, 0,
-                                       blk_rq_cur_bytes(ace->req))) {
-                       /* dev_dbg(ace->dev, "next block; h=%li c=%i\n",
-                        *      ace->req->hard_nr_sectors,
-                        *      ace->req->current_nr_sectors);
+               if (__blk_end_request_cur(ace->req, 0)) {
+                       /* dev_dbg(ace->dev, "next block; h=%u c=%u\n",
+                        *      blk_rq_sectors(ace->req),
+                        *      blk_rq_cur_sectors(ace->req));
                         */
                        ace->data_ptr = ace->req->buffer;
-                       ace->data_count = ace->req->current_nr_sectors * 16;
+                       ace->data_count = blk_rq_cur_sectors(ace->req) * 16;
                        ace_fsm_yieldirq(ace);
                        break;
                }
@@ -978,7 +984,7 @@ static int __devinit ace_setup(struct ace_device *ace)
        ace->queue = blk_init_queue(ace_request, &ace->lock);
        if (ace->queue == NULL)
                goto err_blk_initq;
-       blk_queue_hardsect_size(ace->queue, 512);
+       blk_queue_logical_block_size(ace->queue, 512);
 
        /*
         * Allocate and initialize GD structure
index 80754cdd31190c16d9c65e4e0538b979310b42cb..4575171e5beb1bd754e0fe0ba11600b0fce4ea3f 100644 (file)
@@ -70,15 +70,18 @@ static struct gendisk *z2ram_gendisk;
 static void do_z2_request(struct request_queue *q)
 {
        struct request *req;
-       while ((req = elv_next_request(q)) != NULL) {
-               unsigned long start = req->sector << 9;
-               unsigned long len  = req->current_nr_sectors << 9;
+
+       req = blk_fetch_request(q);
+       while (req) {
+               unsigned long start = blk_rq_pos(req) << 9;
+               unsigned long len  = blk_rq_cur_bytes(req);
+               int err = 0;
 
                if (start + len > z2ram_size) {
                        printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n",
-                               req->sector, req->current_nr_sectors);
-                       end_request(req, 0);
-                       continue;
+                               blk_rq_pos(req), blk_rq_cur_sectors(req));
+                       err = -EIO;
+                       goto done;
                }
                while (len) {
                        unsigned long addr = start & Z2RAM_CHUNKMASK;
@@ -93,7 +96,9 @@ static void do_z2_request(struct request_queue *q)
                        start += size;
                        len -= size;
                }
-               end_request(req, 1);
+       done:
+               if (!__blk_end_request_cur(req, err))
+                       req = blk_fetch_request(q);
        }
 }
 
index af761dc434f638e9ab869a8e8d8508a98adbd175..4895f0e053229bc8c04b568912340ffdbc02a076 100644 (file)
@@ -277,8 +277,8 @@ static int hci_uart_tty_open(struct tty_struct *tty)
        /* FIXME: why is this needed. Note don't use ldisc_ref here as the
           open path is before the ldisc is referencable */
 
-       if (tty->ldisc.ops->flush_buffer)
-               tty->ldisc.ops->flush_buffer(tty);
+       if (tty->ldisc->ops->flush_buffer)
+               tty->ldisc->ops->flush_buffer(tty);
        tty_driver_flush_buffer(tty);
 
        return 0;
@@ -463,7 +463,6 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
                                clear_bit(HCI_UART_PROTO_SET, &hu->flags);
                                return err;
                        }
-                       tty->low_latency = 1;
                } else
                        return -EBUSY;
                break;
index cceace61ef286622b93af85fb5c45d134c289eae..71d1b9bab70b515afbe682cca1de5bc4ca3613cb 100644 (file)
@@ -2101,8 +2101,8 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
                nr = nframes;
                if (cdi->cdda_method == CDDA_BPC_SINGLE)
                        nr = 1;
-               if (nr * CD_FRAMESIZE_RAW > (q->max_sectors << 9))
-                       nr = (q->max_sectors << 9) / CD_FRAMESIZE_RAW;
+               if (nr * CD_FRAMESIZE_RAW > (queue_max_sectors(q) << 9))
+                       nr = (queue_max_sectors(q) << 9) / CD_FRAMESIZE_RAW;
 
                len = nr * CD_FRAMESIZE_RAW;
 
index 2eecb779437b8057cdef2c59d37bbae71930b9c1..b5621f27c4be8052192a56b29f83bd95820594e9 100644 (file)
@@ -584,8 +584,8 @@ static void gdrom_readdisk_dma(struct work_struct *work)
        list_for_each_safe(elem, next, &gdrom_deferred) {
                req = list_entry(elem, struct request, queuelist);
                spin_unlock(&gdrom_lock);
-               block = req->sector/GD_TO_BLK + GD_SESSION_OFFSET;
-               block_cnt = req->nr_sectors/GD_TO_BLK;
+               block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET;
+               block_cnt = blk_rq_sectors(req)/GD_TO_BLK;
                ctrl_outl(PHYSADDR(req->buffer), GDROM_DMA_STARTADDR_REG);
                ctrl_outl(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
                ctrl_outl(1, GDROM_DMA_DIRECTION_REG);
@@ -632,39 +632,35 @@ static void gdrom_readdisk_dma(struct work_struct *work)
                * before handling ending the request */
                spin_lock(&gdrom_lock);
                list_del_init(&req->queuelist);
-               __blk_end_request(req, err, blk_rq_bytes(req));
+               __blk_end_request_all(req, err);
        }
        spin_unlock(&gdrom_lock);
        kfree(read_command);
 }
 
-static void gdrom_request_handler_dma(struct request *req)
-{
-       /* dequeue, add to list of deferred work
-       * and then schedule workqueue */
-       blkdev_dequeue_request(req);
-       list_add_tail(&req->queuelist, &gdrom_deferred);
-       schedule_work(&work);
-}
-
 static void gdrom_request(struct request_queue *rq)
 {
        struct request *req;
 
-       while ((req = elv_next_request(rq)) != NULL) {
+       while ((req = blk_fetch_request(rq)) != NULL) {
                if (!blk_fs_request(req)) {
                        printk(KERN_DEBUG "GDROM: Non-fs request ignored\n");
-                       end_request(req, 0);
+                       __blk_end_request_all(req, -EIO);
+                       continue;
                }
                if (rq_data_dir(req) != READ) {
                        printk(KERN_NOTICE "GDROM: Read only device -");
                        printk(" write request ignored\n");
-                       end_request(req, 0);
+                       __blk_end_request_all(req, -EIO);
+                       continue;
                }
-               if (req->nr_sectors)
-                       gdrom_request_handler_dma(req);
-               else
-                       end_request(req, 0);
+
+               /*
+                * Add to list of deferred work and then schedule
+                * workqueue.
+                */
+               list_add_tail(&req->queuelist, &gdrom_deferred);
+               schedule_work(&work);
        }
 }
 
@@ -743,7 +739,7 @@ static void __devinit probe_gdrom_setupdisk(void)
 
 static int __devinit probe_gdrom_setupqueue(void)
 {
-       blk_queue_hardsect_size(gd.gdrom_rq, GDROM_HARD_SECTOR);
+       blk_queue_logical_block_size(gd.gdrom_rq, GDROM_HARD_SECTOR);
        /* using DMA so memory will need to be contiguous */
        blk_queue_max_hw_segments(gd.gdrom_rq, 1);
        /* set a large max size to get most from DMA */
index 9b1624e0ddeb5ae7615478c67ec03ec2f4a3a0e9..0fff646cc2f0904bc5539d052628420e899a0957 100644 (file)
@@ -282,7 +282,7 @@ static int send_request(struct request *req)
                        viopath_targetinst(viopath_hostLp),
                        (u64)req, VIOVERSION << 16,
                        ((u64)DEVICE_NR(diskinfo) << 48) | dmaaddr,
-                       (u64)req->sector * 512, len, 0);
+                       (u64)blk_rq_pos(req) * 512, len, 0);
        if (hvrc != HvLpEvent_Rc_Good) {
                printk(VIOCD_KERN_WARNING "hv error on op %d\n", (int)hvrc);
                return -1;
@@ -291,36 +291,19 @@ static int send_request(struct request *req)
        return 0;
 }
 
-static void viocd_end_request(struct request *req, int error)
-{
-       int nsectors = req->hard_nr_sectors;
-
-       /*
-        * Make sure it's fully ended, and ensure that we process
-        * at least one sector.
-        */
-       if (blk_pc_request(req))
-               nsectors = (req->data_len + 511) >> 9;
-       if (!nsectors)
-               nsectors = 1;
-
-       if (__blk_end_request(req, error, nsectors << 9))
-               BUG();
-}
-
 static int rwreq;
 
 static void do_viocd_request(struct request_queue *q)
 {
        struct request *req;
 
-       while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) {
+       while ((rwreq == 0) && ((req = blk_fetch_request(q)) != NULL)) {
                if (!blk_fs_request(req))
-                       viocd_end_request(req, -EIO);
+                       __blk_end_request_all(req, -EIO);
                else if (send_request(req) < 0) {
                        printk(VIOCD_KERN_WARNING
                                        "unable to send message to OS/400!");
-                       viocd_end_request(req, -EIO);
+                       __blk_end_request_all(req, -EIO);
                } else
                        rwreq++;
        }
@@ -486,8 +469,8 @@ static void vio_handle_cd_event(struct HvLpEvent *event)
        case viocdopen:
                if (event->xRc == 0) {
                        di = &viocd_diskinfo[bevent->disk];
-                       blk_queue_hardsect_size(di->viocd_disk->queue,
-                                       bevent->block_size);
+                       blk_queue_logical_block_size(di->viocd_disk->queue,
+                                                    bevent->block_size);
                        set_capacity(di->viocd_disk,
                                        bevent->media_size *
                                        bevent->block_size / 512);
@@ -531,9 +514,9 @@ return_complete:
                                        "with rc %d:0x%04X: %s\n",
                                        req, event->xRc,
                                        bevent->sub_result, err->msg);
-                       viocd_end_request(req, -EIO);
+                       __blk_end_request_all(req, -EIO);
                } else
-                       viocd_end_request(req, 0);
+                       __blk_end_request_all(req, 0);
 
                /* restart handling of incoming requests */
                spin_unlock_irqrestore(&viocd_reqlock, flags);
index 735bbe2be51aaf73819078c543320c5fc9111bbc..02ecfd5fa61c56f17ed658e3759e525794f53d81 100644 (file)
@@ -97,6 +97,19 @@ config DEVKMEM
          kind of kernel debugging operations.
          When in doubt, say "N".
 
+config BFIN_JTAG_COMM
+       tristate "Blackfin JTAG Communication"
+       depends on BLACKFIN
+       help
+         Add support for emulating a TTY device over the Blackfin JTAG.
+
+         To compile this driver as a module, choose M here: the
+         module will be called bfin_jtag_comm.
+
+config BFIN_JTAG_COMM_CONSOLE
+       bool "Console on Blackfin JTAG"
+       depends on BFIN_JTAG_COMM=y
+
 config SERIAL_NONSTANDARD
        bool "Non-standard serial port support"
        depends on HAS_IOMEM
index 9caf5b5ad1c05bfbe9ec4f7683a7f1c8c852005e..189efcff08ce246a58900ab15a7cacd487c37724 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_LEGACY_PTYS)     += pty.o
 obj-$(CONFIG_UNIX98_PTYS)      += pty.o
 obj-y                          += misc.o
 obj-$(CONFIG_VT)               += vt_ioctl.o vc_screen.o selection.o keyboard.o
+obj-$(CONFIG_BFIN_JTAG_COMM)   += bfin_jtag_comm.o
 obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
 obj-$(CONFIG_HW_CONSOLE)       += vt.o defkeymap.o
 obj-$(CONFIG_AUDIT)            += tty_audit.o
diff --git a/drivers/char/bfin_jtag_comm.c b/drivers/char/bfin_jtag_comm.c
new file mode 100644 (file)
index 0000000..44c113d
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * TTY over Blackfin JTAG Communication
+ *
+ * Copyright 2008-2009 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/circ_buf.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <asm/atomic.h>
+
+/* See the Debug/Emulation chapter in the HRM */
+#define EMUDOF   0x00000001    /* EMUDAT_OUT full & valid */
+#define EMUDIF   0x00000002    /* EMUDAT_IN full & valid */
+#define EMUDOOVF 0x00000004    /* EMUDAT_OUT overflow */
+#define EMUDIOVF 0x00000008    /* EMUDAT_IN overflow */
+
+#define DRV_NAME "bfin-jtag-comm"
+#define DEV_NAME "ttyBFJC"
+
+#define pr_init(fmt, args...) ({ static const __initdata char __fmt[] = fmt; printk(__fmt, ## args); })
+#define debug(fmt, args...) pr_debug(DRV_NAME ": " fmt, ## args)
+
+static inline uint32_t bfin_write_emudat(uint32_t emudat)
+{
+       __asm__ __volatile__("emudat = %0;" : : "d"(emudat));
+       return emudat;
+}
+
+static inline uint32_t bfin_read_emudat(void)
+{
+       uint32_t emudat;
+       __asm__ __volatile__("%0 = emudat;" : "=d"(emudat));
+       return emudat;
+}
+
+static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d)
+{
+       return bfin_write_emudat((a << 0) | (b << 8) | (c << 16) | (d << 24));
+}
+
+#define CIRC_SIZE 2048 /* see comment in tty_io.c:do_tty_write() */
+#define CIRC_MASK (CIRC_SIZE - 1)
+#define circ_empty(circ)     ((circ)->head == (circ)->tail)
+#define circ_free(circ)      CIRC_SPACE((circ)->head, (circ)->tail, CIRC_SIZE)
+#define circ_cnt(circ)       CIRC_CNT((circ)->head, (circ)->tail, CIRC_SIZE)
+#define circ_byte(circ, idx) ((circ)->buf[(idx) & CIRC_MASK])
+
+static struct tty_driver *bfin_jc_driver;
+static struct task_struct *bfin_jc_kthread;
+static struct tty_struct * volatile bfin_jc_tty;
+static unsigned long bfin_jc_count;
+static DEFINE_MUTEX(bfin_jc_tty_mutex);
+static volatile struct circ_buf bfin_jc_write_buf;
+
+static int
+bfin_jc_emudat_manager(void *arg)
+{
+       uint32_t inbound_len = 0, outbound_len = 0;
+
+       while (!kthread_should_stop()) {
+               /* no one left to give data to, so sleep */
+               if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) {
+                       debug("waiting for readers\n");
+                       __set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule();
+                       __set_current_state(TASK_RUNNING);
+               }
+
+               /* no data available, so just chill */
+               if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
+                       debug("waiting for data (in_len = %i) (circ: %i %i)\n",
+                               inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
+                       if (inbound_len)
+                               schedule();
+                       else
+                               schedule_timeout_interruptible(HZ);
+                       continue;
+               }
+
+               /* if incoming data is ready, eat it */
+               if (bfin_read_DBGSTAT() & EMUDIF) {
+                       struct tty_struct *tty;
+                       mutex_lock(&bfin_jc_tty_mutex);
+                       tty = (struct tty_struct *)bfin_jc_tty;
+                       if (tty != NULL) {
+                               uint32_t emudat = bfin_read_emudat();
+                               if (inbound_len == 0) {
+                                       debug("incoming length: 0x%08x\n", emudat);
+                                       inbound_len = emudat;
+                               } else {
+                                       size_t num_chars = (4 <= inbound_len ? 4 : inbound_len);
+                                       debug("  incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars);
+                                       inbound_len -= num_chars;
+                                       tty_insert_flip_string(tty, (unsigned char *)&emudat, num_chars);
+                                       tty_flip_buffer_push(tty);
+                               }
+                       }
+                       mutex_unlock(&bfin_jc_tty_mutex);
+               }
+
+               /* if outgoing data is ready, post it */
+               if (!(bfin_read_DBGSTAT() & EMUDOF) && !circ_empty(&bfin_jc_write_buf)) {
+                       if (outbound_len == 0) {
+                               outbound_len = circ_cnt(&bfin_jc_write_buf);
+                               bfin_write_emudat(outbound_len);
+                               debug("outgoing length: 0x%08x\n", outbound_len);
+                       } else {
+                               struct tty_struct *tty;
+                               int tail = bfin_jc_write_buf.tail;
+                               size_t ate = (4 <= outbound_len ? 4 : outbound_len);
+                               uint32_t emudat =
+                               bfin_write_emudat_chars(
+                                       circ_byte(&bfin_jc_write_buf, tail + 0),
+                                       circ_byte(&bfin_jc_write_buf, tail + 1),
+                                       circ_byte(&bfin_jc_write_buf, tail + 2),
+                                       circ_byte(&bfin_jc_write_buf, tail + 3)
+                               );
+                               bfin_jc_write_buf.tail += ate;
+                               outbound_len -= ate;
+                               mutex_lock(&bfin_jc_tty_mutex);
+                               tty = (struct tty_struct *)bfin_jc_tty;
+                               if (tty)
+                                       tty_wakeup(tty);
+                               mutex_unlock(&bfin_jc_tty_mutex);
+                               debug("  outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
+                       }
+               }
+       }
+
+       __set_current_state(TASK_RUNNING);
+       return 0;
+}
+
+static int
+bfin_jc_open(struct tty_struct *tty, struct file *filp)
+{
+       mutex_lock(&bfin_jc_tty_mutex);
+       debug("open %lu\n", bfin_jc_count);
+       ++bfin_jc_count;
+       bfin_jc_tty = tty;
+       wake_up_process(bfin_jc_kthread);
+       mutex_unlock(&bfin_jc_tty_mutex);
+       return 0;
+}
+
+static void
+bfin_jc_close(struct tty_struct *tty, struct file *filp)
+{
+       mutex_lock(&bfin_jc_tty_mutex);
+       debug("close %lu\n", bfin_jc_count);
+       if (--bfin_jc_count == 0)
+               bfin_jc_tty = NULL;
+       wake_up_process(bfin_jc_kthread);
+       mutex_unlock(&bfin_jc_tty_mutex);
+}
+
+/* XXX: we dont handle the put_char() case where we must handle count = 1 */
+static int
+bfin_jc_circ_write(const unsigned char *buf, int count)
+{
+       int i;
+       count = min(count, circ_free(&bfin_jc_write_buf));
+       debug("going to write chunk of %i bytes\n", count);
+       for (i = 0; i < count; ++i)
+               circ_byte(&bfin_jc_write_buf, bfin_jc_write_buf.head + i) = buf[i];
+       bfin_jc_write_buf.head += i;
+       return i;
+}
+
+#ifndef CONFIG_BFIN_JTAG_COMM_CONSOLE
+# define acquire_console_sem()
+# define release_console_sem()
+#endif
+static int
+bfin_jc_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+       int i;
+       acquire_console_sem();
+       i = bfin_jc_circ_write(buf, count);
+       release_console_sem();
+       wake_up_process(bfin_jc_kthread);
+       return i;
+}
+
+static void
+bfin_jc_flush_chars(struct tty_struct *tty)
+{
+       wake_up_process(bfin_jc_kthread);
+}
+
+static int
+bfin_jc_write_room(struct tty_struct *tty)
+{
+       return circ_free(&bfin_jc_write_buf);
+}
+
+static int
+bfin_jc_chars_in_buffer(struct tty_struct *tty)
+{
+       return circ_cnt(&bfin_jc_write_buf);
+}
+
+static void
+bfin_jc_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       unsigned long expire = jiffies + timeout;
+       while (!circ_empty(&bfin_jc_write_buf)) {
+               if (signal_pending(current))
+                       break;
+               if (time_after(jiffies, expire))
+                       break;
+       }
+}
+
+static struct tty_operations bfin_jc_ops = {
+       .open            = bfin_jc_open,
+       .close           = bfin_jc_close,
+       .write           = bfin_jc_write,
+       /*.put_char        = bfin_jc_put_char,*/
+       .flush_chars     = bfin_jc_flush_chars,
+       .write_room      = bfin_jc_write_room,
+       .chars_in_buffer = bfin_jc_chars_in_buffer,
+       .wait_until_sent = bfin_jc_wait_until_sent,
+};
+
+static int __init bfin_jc_init(void)
+{
+       int ret;
+
+       bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
+       if (IS_ERR(bfin_jc_kthread))
+               return PTR_ERR(bfin_jc_kthread);
+
+       ret = -ENOMEM;
+
+       bfin_jc_write_buf.head = bfin_jc_write_buf.tail = 0;
+       bfin_jc_write_buf.buf = kmalloc(CIRC_SIZE, GFP_KERNEL);
+       if (!bfin_jc_write_buf.buf)
+               goto err;
+
+       bfin_jc_driver = alloc_tty_driver(1);
+       if (!bfin_jc_driver)
+               goto err;
+
+       bfin_jc_driver->owner        = THIS_MODULE;
+       bfin_jc_driver->driver_name  = DRV_NAME;
+       bfin_jc_driver->name         = DEV_NAME;
+       bfin_jc_driver->type         = TTY_DRIVER_TYPE_SERIAL;
+       bfin_jc_driver->subtype      = SERIAL_TYPE_NORMAL;
+       bfin_jc_driver->init_termios = tty_std_termios;
+       tty_set_operations(bfin_jc_driver, &bfin_jc_ops);
+
+       ret = tty_register_driver(bfin_jc_driver);
+       if (ret)
+               goto err;
+
+       pr_init(KERN_INFO DRV_NAME ": initialized\n");
+
+       return 0;
+
+ err:
+       put_tty_driver(bfin_jc_driver);
+       kfree(bfin_jc_write_buf.buf);
+       kthread_stop(bfin_jc_kthread);
+       return ret;
+}
+module_init(bfin_jc_init);
+
+static void __exit bfin_jc_exit(void)
+{
+       kthread_stop(bfin_jc_kthread);
+       kfree(bfin_jc_write_buf.buf);
+       tty_unregister_driver(bfin_jc_driver);
+       put_tty_driver(bfin_jc_driver);
+}
+module_exit(bfin_jc_exit);
+
+#if defined(CONFIG_BFIN_JTAG_COMM_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+static void
+bfin_jc_straight_buffer_write(const char *buf, unsigned count)
+{
+       unsigned ate = 0;
+       while (bfin_read_DBGSTAT() & EMUDOF)
+               continue;
+       bfin_write_emudat(count);
+       while (ate < count) {
+               while (bfin_read_DBGSTAT() & EMUDOF)
+                       continue;
+               bfin_write_emudat_chars(buf[ate], buf[ate+1], buf[ate+2], buf[ate+3]);
+               ate += 4;
+       }
+}
+#endif
+
+#ifdef CONFIG_BFIN_JTAG_COMM_CONSOLE
+static void
+bfin_jc_console_write(struct console *co, const char *buf, unsigned count)
+{
+       if (bfin_jc_kthread == NULL)
+               bfin_jc_straight_buffer_write(buf, count);
+       else
+               bfin_jc_circ_write(buf, count);
+}
+
+static struct tty_driver *
+bfin_jc_console_device(struct console *co, int *index)
+{
+       *index = co->index;
+       return bfin_jc_driver;
+}
+
+static struct console bfin_jc_console = {
+       .name    = DEV_NAME,
+       .write   = bfin_jc_console_write,
+       .device  = bfin_jc_console_device,
+       .flags   = CON_ANYTIME | CON_PRINTBUFFER,
+       .index   = -1,
+};
+
+static int __init bfin_jc_console_init(void)
+{
+       register_console(&bfin_jc_console);
+       return 0;
+}
+console_initcall(bfin_jc_console_init);
+#endif
+
+#ifdef CONFIG_EARLY_PRINTK
+static void __init
+bfin_jc_early_write(struct console *co, const char *buf, unsigned int count)
+{
+       bfin_jc_straight_buffer_write(buf, count);
+}
+
+static struct __initdata console bfin_jc_early_console = {
+       .name   = "early_BFJC",
+       .write   = bfin_jc_early_write,
+       .flags   = CON_ANYTIME | CON_PRINTBUFFER,
+       .index   = -1,
+};
+
+struct console * __init
+bfin_jc_early_init(unsigned int port, unsigned int cflag)
+{
+       return &bfin_jc_early_console;
+}
+#endif
+
+MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
+MODULE_DESCRIPTION("TTY over Blackfin JTAG Communication");
+MODULE_LICENSE("GPL");
index 1fdb9f657d8f8650745ab136b7292d887568be7e..f3366d3f06cfe404cdfe94b6d3393c55b7b05886 100644 (file)
 
 #define NR_PORTS       256
 
-#define ZE_V1_NPORTS   64
 #define ZO_V1  0
 #define ZO_V2  1
 #define ZE_V1  2
 static void cy_throttle(struct tty_struct *tty);
 static void cy_send_xchar(struct tty_struct *tty, char ch);
 
-#define IS_CYC_Z(card) ((card).num_chips == (unsigned int)-1)
-
-#define Z_FPGA_CHECK(card) \
-       ((readl(&((struct RUNTIME_9060 __iomem *) \
-               ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
-
-#define ISZLOADED(card)        (((ZO_V1 == readl(&((struct RUNTIME_9060 __iomem *) \
-                       ((card).ctl_addr))->mail_box_0)) || \
-                       Z_FPGA_CHECK(card)) && \
-                       (ZFIRM_ID == readl(&((struct FIRM_ID __iomem *) \
-                       ((card).base_addr+ID_ADDRESS))->signature)))
-
 #ifndef SERIAL_XMIT_SIZE
 #define        SERIAL_XMIT_SIZE        (min(PAGE_SIZE, 4096))
 #endif
@@ -687,8 +674,6 @@ static void cy_send_xchar(struct tty_struct *tty, char ch);
 #define DRIVER_VERSION 0x02010203
 #define RAM_SIZE 0x80000
 
-#define Z_FPGA_LOADED(X)       ((readl(&(X)->init_ctrl) & (1<<17)) != 0)
-
 enum zblock_type {
        ZBLOCK_PRG = 0,
        ZBLOCK_FPGA = 1
@@ -883,6 +868,29 @@ static void cyz_rx_restart(unsigned long);
 static struct timer_list cyz_rx_full_timer[NR_PORTS];
 #endif                         /* CONFIG_CYZ_INTR */
 
+static inline bool cy_is_Z(struct cyclades_card *card)
+{
+       return card->num_chips == (unsigned int)-1;
+}
+
+static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
+{
+       return readl(&ctl_addr->init_ctrl) & (1 << 17);
+}
+
+static inline bool cyz_fpga_loaded(struct cyclades_card *card)
+{
+       return __cyz_fpga_loaded(card->ctl_addr.p9060);
+}
+
+static inline bool cyz_is_loaded(struct cyclades_card *card)
+{
+       struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
+
+       return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
+                       readl(&fw_id->signature) == ZFIRM_ID;
+}
+
 static inline int serial_paranoia_check(struct cyclades_port *info,
                char *name, const char *routine)
 {
@@ -1395,19 +1403,15 @@ cyz_fetch_msg(struct cyclades_card *cinfo,
        unsigned long loc_doorbell;
 
        firm_id = cinfo->base_addr + ID_ADDRESS;
-       if (!ISZLOADED(*cinfo))
-               return -1;
        zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
        board_ctrl = &zfw_ctrl->board_ctrl;
 
-       loc_doorbell = readl(&((struct RUNTIME_9060 __iomem *)
-                                 (cinfo->ctl_addr))->loc_doorbell);
+       loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
        if (loc_doorbell) {
                *cmd = (char)(0xff & loc_doorbell);
                *channel = readl(&board_ctrl->fwcmd_channel);
                *param = (__u32) readl(&board_ctrl->fwcmd_param);
-               cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
-                         loc_doorbell, 0xffffffff);
+               cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
                return 1;
        }
        return 0;
@@ -1424,15 +1428,14 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
        unsigned int index;
 
        firm_id = cinfo->base_addr + ID_ADDRESS;
-       if (!ISZLOADED(*cinfo))
+       if (!cyz_is_loaded(cinfo))
                return -1;
 
        zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
        board_ctrl = &zfw_ctrl->board_ctrl;
 
        index = 0;
-       pci_doorbell =
-           &((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell;
+       pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
        while ((readl(pci_doorbell) & 0xff) != 0) {
                if (index++ == 1000)
                        return (int)(readl(pci_doorbell) & 0xff);
@@ -1624,10 +1627,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
        static struct BOARD_CTRL __iomem *board_ctrl;
        static struct CH_CTRL __iomem *ch_ctrl;
        static struct BUF_CTRL __iomem *buf_ctrl;
-       __u32 channel;
+       __u32 channel, param, fw_ver;
        __u8 cmd;
-       __u32 param;
-       __u32 hw_ver, fw_ver;
        int special_count;
        int delta_count;
 
@@ -1635,8 +1636,6 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
        zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
        board_ctrl = &zfw_ctrl->board_ctrl;
        fw_ver = readl(&board_ctrl->fw_version);
-       hw_ver = readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
-                       mail_box_0);
 
        while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
                special_count = 0;
@@ -1737,15 +1736,7 @@ static irqreturn_t cyz_interrupt(int irq, void *dev_id)
 {
        struct cyclades_card *cinfo = dev_id;
 
-       if (unlikely(cinfo == NULL)) {
-#ifdef CY_DEBUG_INTERRUPTS
-               printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",
-                                                                       irq);
-#endif
-               return IRQ_NONE;        /* spurious interrupt */
-       }
-
-       if (unlikely(!ISZLOADED(*cinfo))) {
+       if (unlikely(!cyz_is_loaded(cinfo))) {
 #ifdef CY_DEBUG_INTERRUPTS
                printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
                                "(IRQ%d).\n", irq);
@@ -1785,7 +1776,6 @@ static void cyz_poll(unsigned long arg)
        struct tty_struct *tty;
        struct FIRM_ID __iomem *firm_id;
        struct ZFW_CTRL __iomem *zfw_ctrl;
-       struct BOARD_CTRL __iomem *board_ctrl;
        struct BUF_CTRL __iomem *buf_ctrl;
        unsigned long expires = jiffies + HZ;
        unsigned int port, card;
@@ -1793,19 +1783,17 @@ static void cyz_poll(unsigned long arg)
        for (card = 0; card < NR_CARDS; card++) {
                cinfo = &cy_card[card];
 
-               if (!IS_CYC_Z(*cinfo))
+               if (!cy_is_Z(cinfo))
                        continue;
-               if (!ISZLOADED(*cinfo))
+               if (!cyz_is_loaded(cinfo))
                        continue;
 
                firm_id = cinfo->base_addr + ID_ADDRESS;
                zfw_ctrl = cinfo->base_addr +
                                (readl(&firm_id->zfwctrl_addr) & 0xfffff);
-               board_ctrl = &(zfw_ctrl->board_ctrl);
 
        /* Skip first polling cycle to avoid racing conditions with the FW */
                if (!cinfo->intr_enabled) {
-                       cinfo->nports = (int)readl(&board_ctrl->n_channel);
                        cinfo->intr_enabled = 1;
                        continue;
                }
@@ -1874,7 +1862,7 @@ static int startup(struct cyclades_port *info)
 
        set_line_char(info);
 
-       if (!IS_CYC_Z(*card)) {
+       if (!cy_is_Z(card)) {
                chip = channel >> 2;
                channel &= 0x03;
                index = card->bus_index;
@@ -1931,7 +1919,7 @@ static int startup(struct cyclades_port *info)
                base_addr = card->base_addr;
 
                firm_id = base_addr + ID_ADDRESS;
-               if (!ISZLOADED(*card))
+               if (!cyz_is_loaded(card))
                        return -ENODEV;
 
                zfw_ctrl = card->base_addr +
@@ -2026,7 +2014,7 @@ static void start_xmit(struct cyclades_port *info)
 
        card = info->card;
        channel = info->line - card->first_line;
-       if (!IS_CYC_Z(*card)) {
+       if (!cy_is_Z(card)) {
                chip = channel >> 2;
                channel &= 0x03;
                index = card->bus_index;
@@ -2070,7 +2058,7 @@ static void shutdown(struct cyclades_port *info)
 
        card = info->card;
        channel = info->line - card->first_line;
-       if (!IS_CYC_Z(*card)) {
+       if (!cy_is_Z(card)) {
                chip = channel >> 2;
                channel &= 0x03;
                index = card->bus_index;
@@ -2126,7 +2114,7 @@ static void shutdown(struct cyclades_port *info)
 #endif
 
                firm_id = base_addr + ID_ADDRESS;
-               if (!ISZLOADED(*card))
+               if (!cyz_is_loaded(card))
                        return;
 
                zfw_ctrl = card->base_addr +
@@ -2233,7 +2221,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
 #endif
        info->port.blocked_open++;
 
-       if (!IS_CYC_Z(*cinfo)) {
+       if (!cy_is_Z(cinfo)) {
                chip = channel >> 2;
                channel &= 0x03;
                index = cinfo->bus_index;
@@ -2296,7 +2284,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
 
                base_addr = cinfo->base_addr;
                firm_id = base_addr + ID_ADDRESS;
-               if (!ISZLOADED(*cinfo)) {
+               if (!cyz_is_loaded(cinfo)) {
                        __set_current_state(TASK_RUNNING);
                        remove_wait_queue(&info->port.open_wait, &wait);
                        return -EINVAL;
@@ -2397,16 +2385,14 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
           treat it as absent from the system.  This
           will make the user pay attention.
         */
-       if (IS_CYC_Z(*info->card)) {
+       if (cy_is_Z(info->card)) {
                struct cyclades_card *cinfo = info->card;
                struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
 
-               if (!ISZLOADED(*cinfo)) {
-                       if (((ZE_V1 == readl(&((struct RUNTIME_9060 __iomem *)
-                                        (cinfo->ctl_addr))->mail_box_0)) &&
-                                       Z_FPGA_CHECK(*cinfo)) &&
-                                       (ZFIRM_HLT == readl(
-                                               &firm_id->signature))) {
+               if (!cyz_is_loaded(cinfo)) {
+                       if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
+                                       readl(&firm_id->signature) ==
+                                       ZFIRM_HLT) {
                                printk(KERN_ERR "cyc:Cyclades-Z Error: you "
                                        "need an external power supply for "
                                        "this number of ports.\nFirmware "
@@ -2423,18 +2409,13 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
                   interrupts should be enabled as soon as the first open
                   happens to one of its ports. */
                        if (!cinfo->intr_enabled) {
-                               struct ZFW_CTRL __iomem *zfw_ctrl;
-                               struct BOARD_CTRL __iomem *board_ctrl;
-
-                               zfw_ctrl = cinfo->base_addr +
-                                       (readl(&firm_id->zfwctrl_addr) &
-                                        0xfffff);
-
-                               board_ctrl = &zfw_ctrl->board_ctrl;
+                               u16 intr;
 
                                /* Enable interrupts on the PLX chip */
-                               cy_writew(cinfo->ctl_addr + 0x68,
-                                       readw(cinfo->ctl_addr + 0x68) | 0x0900);
+                               intr = readw(&cinfo->ctl_addr.p9060->
+                                               intr_ctrl_stat) | 0x0900;
+                               cy_writew(&cinfo->ctl_addr.p9060->
+                                               intr_ctrl_stat, intr);
                                /* Enable interrupts on the FW */
                                retval = cyz_issue_cmd(cinfo, 0,
                                                C_CM_IRQ_ENBL, 0L);
@@ -2442,8 +2423,6 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
                                        printk(KERN_ERR "cyc:IRQ enable retval "
                                                "was %x\n", retval);
                                }
-                               cinfo->nports =
-                                       (int)readl(&board_ctrl->n_channel);
                                cinfo->intr_enabled = 1;
                        }
                }
@@ -2556,7 +2535,7 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
 #endif
        card = info->card;
        channel = (info->line) - (card->first_line);
-       if (!IS_CYC_Z(*card)) {
+       if (!cy_is_Z(card)) {
                chip = channel >> 2;
                channel &= 0x03;
                index = card->bus_index;
@@ -2601,7 +2580,7 @@ static void cy_flush_buffer(struct tty_struct *tty)
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
        spin_unlock_irqrestore(&card->card_lock, flags);
 
-       if (IS_CYC_Z(*card)) {  /* If it is a Z card, flush the on-board
+       if (cy_is_Z(card)) {    /* If it is a Z card, flush the on-board
                                           buffers as well */
                spin_lock_irqsave(&card->card_lock, flags);
                retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
@@ -2682,7 +2661,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
 
        spin_lock_irqsave(&card->card_lock, flags);
 
-       if (!IS_CYC_Z(*card)) {
+       if (!cy_is_Z(card)) {
                int channel = info->line - card->first_line;
                int index = card->bus_index;
                void __iomem *base_addr = card->base_addr +
@@ -2902,7 +2881,7 @@ static int cy_chars_in_buffer(struct tty_struct *tty)
        channel = (info->line) - (card->first_line);
 
 #ifdef Z_EXT_CHARS_IN_BUFFER
-       if (!IS_CYC_Z(cy_card[card])) {
+       if (!cy_is_Z(card)) {
 #endif                         /* Z_EXT_CHARS_IN_BUFFER */
 #ifdef CY_DEBUG_IO
                printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
@@ -2984,7 +2963,6 @@ static void set_line_char(struct cyclades_port *info)
        void __iomem *base_addr;
        int chip, channel, index;
        unsigned cflag, iflag;
-       unsigned short chip_number;
        int baud, baud_rate = 0;
        int i;
 
@@ -3013,9 +2991,8 @@ static void set_line_char(struct cyclades_port *info)
 
        card = info->card;
        channel = info->line - card->first_line;
-       chip_number = channel / 4;
 
-       if (!IS_CYC_Z(*card)) {
+       if (!cy_is_Z(card)) {
 
                index = card->bus_index;
 
@@ -3233,21 +3210,17 @@ static void set_line_char(struct cyclades_port *info)
        } else {
                struct FIRM_ID __iomem *firm_id;
                struct ZFW_CTRL __iomem *zfw_ctrl;
-               struct BOARD_CTRL __iomem *board_ctrl;
                struct CH_CTRL __iomem *ch_ctrl;
-               struct BUF_CTRL __iomem *buf_ctrl;
                __u32 sw_flow;
                int retval;
 
                firm_id = card->base_addr + ID_ADDRESS;
-               if (!ISZLOADED(*card))
+               if (!cyz_is_loaded(card))
                        return;
 
                zfw_ctrl = card->base_addr +
                        (readl(&firm_id->zfwctrl_addr) & 0xfffff);
-               board_ctrl = &zfw_ctrl->board_ctrl;
                ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
-               buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
 
                /* baud rate */
                baud = tty_get_baud_rate(info->port.tty);
@@ -3457,7 +3430,7 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
 
        card = info->card;
        channel = (info->line) - (card->first_line);
-       if (!IS_CYC_Z(*card)) {
+       if (!cy_is_Z(card)) {
                chip = channel >> 2;
                channel &= 0x03;
                index = card->bus_index;
@@ -3497,7 +3470,7 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
 
        card = info->card;
        channel = info->line - card->first_line;
-       if (!IS_CYC_Z(*card)) {
+       if (!cy_is_Z(card)) {
                chip = channel >> 2;
                channel &= 0x03;
                index = card->bus_index;
@@ -3523,7 +3496,7 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
        } else {
                base_addr = card->base_addr;
                firm_id = card->base_addr + ID_ADDRESS;
-               if (ISZLOADED(*card)) {
+               if (cyz_is_loaded(card)) {
                        zfw_ctrl = card->base_addr +
                                (readl(&firm_id->zfwctrl_addr) & 0xfffff);
                        board_ctrl = &zfw_ctrl->board_ctrl;
@@ -3566,7 +3539,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
 
        card = info->card;
        channel = (info->line) - (card->first_line);
-       if (!IS_CYC_Z(*card)) {
+       if (!cy_is_Z(card)) {
                chip = channel >> 2;
                channel &= 0x03;
                index = card->bus_index;
@@ -3641,7 +3614,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
                base_addr = card->base_addr;
 
                firm_id = card->base_addr + ID_ADDRESS;
-               if (ISZLOADED(*card)) {
+               if (cyz_is_loaded(card)) {
                        zfw_ctrl = card->base_addr +
                                (readl(&firm_id->zfwctrl_addr) & 0xfffff);
                        board_ctrl = &zfw_ctrl->board_ctrl;
@@ -3713,7 +3686,7 @@ static int cy_break(struct tty_struct *tty, int break_state)
        card = info->card;
 
        spin_lock_irqsave(&card->card_lock, flags);
-       if (!IS_CYC_Z(*card)) {
+       if (!cy_is_Z(card)) {
                /* Let the transmit ISR take care of this (since it
                   requires stuffing characters into the output stream).
                 */
@@ -3782,7 +3755,7 @@ static int set_threshold(struct cyclades_port *info, unsigned long value)
 
        card = info->card;
        channel = info->line - card->first_line;
-       if (!IS_CYC_Z(*card)) {
+       if (!cy_is_Z(card)) {
                chip = channel >> 2;
                channel &= 0x03;
                index = card->bus_index;
@@ -3810,7 +3783,7 @@ static int get_threshold(struct cyclades_port *info,
 
        card = info->card;
        channel = info->line - card->first_line;
-       if (!IS_CYC_Z(*card)) {
+       if (!cy_is_Z(card)) {
                chip = channel >> 2;
                channel &= 0x03;
                index = card->bus_index;
@@ -3844,7 +3817,7 @@ static int set_timeout(struct cyclades_port *info, unsigned long value)
 
        card = info->card;
        channel = info->line - card->first_line;
-       if (!IS_CYC_Z(*card)) {
+       if (!cy_is_Z(card)) {
                chip = channel >> 2;
                channel &= 0x03;
                index = card->bus_index;
@@ -3867,7 +3840,7 @@ static int get_timeout(struct cyclades_port *info,
 
        card = info->card;
        channel = info->line - card->first_line;
-       if (!IS_CYC_Z(*card)) {
+       if (!cy_is_Z(card)) {
                chip = channel >> 2;
                channel &= 0x03;
                index = card->bus_index;
@@ -4121,7 +4094,7 @@ static void cy_send_xchar(struct tty_struct *tty, char ch)
        card = info->card;
        channel = info->line - card->first_line;
 
-       if (IS_CYC_Z(*card)) {
+       if (cy_is_Z(card)) {
                if (ch == STOP_CHAR(tty))
                        cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
                else if (ch == START_CHAR(tty))
@@ -4154,7 +4127,7 @@ static void cy_throttle(struct tty_struct *tty)
        card = info->card;
 
        if (I_IXOFF(tty)) {
-               if (!IS_CYC_Z(*card))
+               if (!cy_is_Z(card))
                        cy_send_xchar(tty, STOP_CHAR(tty));
                else
                        info->throttle = 1;
@@ -4162,7 +4135,7 @@ static void cy_throttle(struct tty_struct *tty)
 
        if (tty->termios->c_cflag & CRTSCTS) {
                channel = info->line - card->first_line;
-               if (!IS_CYC_Z(*card)) {
+               if (!cy_is_Z(card)) {
                        chip = channel >> 2;
                        channel &= 0x03;
                        index = card->bus_index;
@@ -4219,7 +4192,7 @@ static void cy_unthrottle(struct tty_struct *tty)
        if (tty->termios->c_cflag & CRTSCTS) {
                card = info->card;
                channel = info->line - card->first_line;
-               if (!IS_CYC_Z(*card)) {
+               if (!cy_is_Z(card)) {
                        chip = channel >> 2;
                        channel &= 0x03;
                        index = card->bus_index;
@@ -4263,7 +4236,7 @@ static void cy_stop(struct tty_struct *tty)
 
        cinfo = info->card;
        channel = info->line - cinfo->first_line;
-       if (!IS_CYC_Z(*cinfo)) {
+       if (!cy_is_Z(cinfo)) {
                index = cinfo->bus_index;
                chip = channel >> 2;
                channel &= 0x03;
@@ -4296,7 +4269,7 @@ static void cy_start(struct tty_struct *tty)
        cinfo = info->card;
        channel = info->line - cinfo->first_line;
        index = cinfo->bus_index;
-       if (!IS_CYC_Z(*cinfo)) {
+       if (!cy_is_Z(cinfo)) {
                chip = channel >> 2;
                channel &= 0x03;
                base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
@@ -4347,33 +4320,20 @@ static void cy_hangup(struct tty_struct *tty)
 static int __devinit cy_init_card(struct cyclades_card *cinfo)
 {
        struct cyclades_port *info;
-       u32 uninitialized_var(mailbox);
-       unsigned int nports, port;
+       unsigned int port;
        unsigned short chip_number;
-       int uninitialized_var(index);
 
        spin_lock_init(&cinfo->card_lock);
+       cinfo->intr_enabled = 0;
 
-       if (IS_CYC_Z(*cinfo)) { /* Cyclades-Z */
-               mailbox = readl(&((struct RUNTIME_9060 __iomem *)
-                                    cinfo->ctl_addr)->mail_box_0);
-               nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
-               cinfo->intr_enabled = 0;
-               cinfo->nports = 0;      /* Will be correctly set later, after
-                                          Z FW is loaded */
-       } else {
-               index = cinfo->bus_index;
-               nports = cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
-       }
-
-       cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL);
+       cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
+                       GFP_KERNEL);
        if (cinfo->ports == NULL) {
                printk(KERN_ERR "Cyclades: cannot allocate ports\n");
-               cinfo->nports = 0;
                return -ENOMEM;
        }
 
-       for (port = cinfo->first_line; port < cinfo->first_line + nports;
+       for (port = cinfo->first_line; port < cinfo->first_line + cinfo->nports;
                        port++) {
                info = &cinfo->ports[port - cinfo->first_line];
                tty_port_init(&info->port);
@@ -4387,9 +4347,9 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
                init_completion(&info->shutdown_wait);
                init_waitqueue_head(&info->delta_msr_wait);
 
-               if (IS_CYC_Z(*cinfo)) {
+               if (cy_is_Z(cinfo)) {
                        info->type = PORT_STARTECH;
-                       if (mailbox == ZO_V1)
+                       if (cinfo->hw_ver == ZO_V1)
                                info->xmit_fifo_size = CYZ_FIFO_SIZE;
                        else
                                info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
@@ -4398,6 +4358,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
                                cyz_rx_restart, (unsigned long)info);
 #endif
                } else {
+                       int index = cinfo->bus_index;
                        info->type = PORT_CIRRUS;
                        info->xmit_fifo_size = CyMAX_CHAR_FIFO;
                        info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
@@ -4430,7 +4391,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
        }
 
 #ifndef CONFIG_CYZ_INTR
-       if (IS_CYC_Z(*cinfo) && !timer_pending(&cyz_timerlist)) {
+       if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
                mod_timer(&cyz_timerlist, jiffies + 1);
 #ifdef CY_PCI_DEBUG
                printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
@@ -4621,11 +4582,12 @@ static int __init cy_detect_isa(void)
 
                /* set cy_card */
                cy_card[j].base_addr = cy_isa_address;
-               cy_card[j].ctl_addr = NULL;
+               cy_card[j].ctl_addr.p9050 = NULL;
                cy_card[j].irq = (int)cy_isa_irq;
                cy_card[j].bus_index = 0;
                cy_card[j].first_line = cy_next_channel;
-               cy_card[j].num_chips = cy_isa_nchan / 4;
+               cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
+               cy_card[j].nports = cy_isa_nchan;
                if (cy_init_card(&cy_card[j])) {
                        cy_card[j].base_addr = NULL;
                        free_irq(cy_isa_irq, &cy_card[j]);
@@ -4781,7 +4743,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
        struct CUSTOM_REG __iomem *cust = base_addr;
        struct ZFW_CTRL __iomem *pt_zfwctrl;
        void __iomem *tmp;
-       u32 mailbox, status;
+       u32 mailbox, status, nchan;
        unsigned int i;
        int retval;
 
@@ -4793,7 +4755,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
 
        /* Check whether the firmware is already loaded and running. If
           positive, skip this board */
-       if (Z_FPGA_LOADED(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
+       if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
                u32 cntval = readl(base_addr + 0x190);
 
                udelay(100);
@@ -4812,7 +4774,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
 
        mailbox = readl(&ctl_addr->mail_box_0);
 
-       if (mailbox == 0 || Z_FPGA_LOADED(ctl_addr)) {
+       if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
                /* stops CPU and set window to beginning of RAM */
                cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
                cy_writel(&cust->cpu_stop, 0);
@@ -4828,7 +4790,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
                                base_addr);
                if (retval)
                        goto err_rel;
-               if (!Z_FPGA_LOADED(ctl_addr)) {
+               if (!__cyz_fpga_loaded(ctl_addr)) {
                        dev_err(&pdev->dev, "fw upload successful, but fw is "
                                        "not loaded\n");
                        goto err_rel;
@@ -4887,7 +4849,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
                                "system before loading the new FW to the "
                                "Cyclades-Z.\n");
 
-                       if (Z_FPGA_LOADED(ctl_addr))
+                       if (__cyz_fpga_loaded(ctl_addr))
                                plx_init(pdev, irq, ctl_addr);
 
                        retval = -EIO;
@@ -4902,16 +4864,16 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
                        base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
                        base_addr + readl(&fid->zfwctrl_addr));
 
+       nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
        dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
-               readl(&pt_zfwctrl->board_ctrl.fw_version),
-               readl(&pt_zfwctrl->board_ctrl.n_channel));
+               readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
 
-       if (readl(&pt_zfwctrl->board_ctrl.n_channel) == 0) {
+       if (nchan == 0) {
                dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
                        "check the connection between the Z host card and the "
                        "serial expanders.\n");
 
-               if (Z_FPGA_LOADED(ctl_addr))
+               if (__cyz_fpga_loaded(ctl_addr))
                        plx_init(pdev, irq, ctl_addr);
 
                dev_info(&pdev->dev, "Null number of ports detected. Board "
@@ -4932,9 +4894,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
        cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
                        0x00030800UL);
 
-       plx_init(pdev, irq, ctl_addr);
-
-       return 0;
+       return nchan;
 err_rel:
        release_firmware(fw);
 err:
@@ -4946,7 +4906,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
 {
        void __iomem *addr0 = NULL, *addr2 = NULL;
        char *card_name = NULL;
-       u32 mailbox;
+       u32 uninitialized_var(mailbox);
        unsigned int device_id, nchan = 0, card_no, i;
        unsigned char plx_ver;
        int retval, irq;
@@ -5023,11 +4983,12 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
                }
 
                /* Disable interrupts on the PLX before resetting it */
-               cy_writew(addr0 + 0x68, readw(addr0 + 0x68) & ~0x0900);
+               cy_writew(&ctl_addr->intr_ctrl_stat,
+                               readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
 
                plx_init(pdev, irq, addr0);
 
-               mailbox = (u32)readl(&ctl_addr->mail_box_0);
+               mailbox = readl(&ctl_addr->mail_box_0);
 
                addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
                                mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
@@ -5038,12 +4999,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
 
                if (mailbox == ZE_V1) {
                        card_name = "Cyclades-Ze";
-
-                       readl(&ctl_addr->mail_box_0);
-                       nchan = ZE_V1_NPORTS;
                } else {
                        card_name = "Cyclades-8Zo";
-
 #ifdef CY_PCI_DEBUG
                        if (mailbox == ZO_V1) {
                                cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
@@ -5065,15 +5022,12 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
                         */
                        if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
                                cy_writel(addr2 + ID_ADDRESS, 0L);
-
-                       retval = cyz_load_fw(pdev, addr2, addr0, irq);
-                       if (retval)
-                               goto err_unmap;
-                       /* This must be a Cyclades-8Zo/PCI.  The extendable
-                          version will have a different device_id and will
-                          be allocated its maximum number of ports. */
-                       nchan = 8;
                }
+
+               retval = cyz_load_fw(pdev, addr2, addr0, irq);
+               if (retval <= 0)
+                       goto err_unmap;
+               nchan = retval;
        }
 
        if ((cy_next_channel + nchan) > NR_PORTS) {
@@ -5103,8 +5057,10 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
                        dev_err(&pdev->dev, "could not allocate IRQ\n");
                        goto err_unmap;
                }
-               cy_card[card_no].num_chips = nchan / 4;
+               cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
        } else {
+               cy_card[card_no].hw_ver = mailbox;
+               cy_card[card_no].num_chips = (unsigned int)-1;
 #ifdef CONFIG_CYZ_INTR
                /* allocate IRQ only if board has an IRQ */
                if (irq != 0 && irq != 255) {
@@ -5117,15 +5073,15 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
                        }
                }
 #endif                         /* CONFIG_CYZ_INTR */
-               cy_card[card_no].num_chips = (unsigned int)-1;
        }
 
        /* set cy_card */
        cy_card[card_no].base_addr = addr2;
-       cy_card[card_no].ctl_addr = addr0;
+       cy_card[card_no].ctl_addr.p9050 = addr0;
        cy_card[card_no].irq = irq;
        cy_card[card_no].bus_index = 1;
        cy_card[card_no].first_line = cy_next_channel;
+       cy_card[card_no].nports = nchan;
        retval = cy_init_card(&cy_card[card_no]);
        if (retval)
                goto err_null;
@@ -5138,17 +5094,20 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
                plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
                switch (plx_ver) {
                case PLX_9050:
-
                        cy_writeb(addr0 + 0x4c, 0x43);
                        break;
 
                case PLX_9060:
                case PLX_9080:
                default:        /* Old boards, use PLX_9060 */
-                       plx_init(pdev, irq, addr0);
-                       cy_writew(addr0 + 0x68, readw(addr0 + 0x68) | 0x0900);
+               {
+                       struct RUNTIME_9060 __iomem *ctl_addr = addr0;
+                       plx_init(pdev, irq, ctl_addr);
+                       cy_writew(&ctl_addr->intr_ctrl_stat,
+                               readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
                        break;
                }
+               }
        }
 
        dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
@@ -5179,22 +5138,23 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev)
        unsigned int i;
 
        /* non-Z with old PLX */
-       if (!IS_CYC_Z(*cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
+       if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
                        PLX_9050)
-               cy_writeb(cinfo->ctl_addr + 0x4c, 0);
+               cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
        else
 #ifndef CONFIG_CYZ_INTR
-               if (!IS_CYC_Z(*cinfo))
+               if (!cy_is_Z(cinfo))
 #endif
-               cy_writew(cinfo->ctl_addr + 0x68,
-                               readw(cinfo->ctl_addr + 0x68) & ~0x0900);
+               cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
+                       readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
+                       ~0x0900);
 
        iounmap(cinfo->base_addr);
-       if (cinfo->ctl_addr)
-               iounmap(cinfo->ctl_addr);
+       if (cinfo->ctl_addr.p9050)
+               iounmap(cinfo->ctl_addr.p9050);
        if (cinfo->irq
 #ifndef CONFIG_CYZ_INTR
-               && !IS_CYC_Z(*cinfo)
+               && !cy_is_Z(cinfo)
 #endif /* CONFIG_CYZ_INTR */
                )
                free_irq(cinfo->irq, cinfo);
@@ -5240,7 +5200,7 @@ static int cyclades_proc_show(struct seq_file *m, void *v)
                                        (cur_jifs - info->idle_stats.recv_idle)/
                                        HZ, info->idle_stats.overruns,
                                        /* FIXME: double check locking */
-                                       (long)info->port.tty->ldisc.ops->num);
+                                       (long)info->port.tty->ldisc->ops->num);
                        else
                                seq_printf(m, "%3d %8lu %10lu %8lu "
                                        "%10lu %8lu %9lu %6ld\n",
@@ -5386,11 +5346,11 @@ static void __exit cy_cleanup_module(void)
                        /* clear interrupt */
                        cy_writeb(card->base_addr + Cy_ClrIntr, 0);
                        iounmap(card->base_addr);
-                       if (card->ctl_addr)
-                               iounmap(card->ctl_addr);
+                       if (card->ctl_addr.p9050)
+                               iounmap(card->ctl_addr.p9050);
                        if (card->irq
 #ifndef CONFIG_CYZ_INTR
-                               && !IS_CYC_Z(*card)
+                               && !cy_is_Z(card)
 #endif /* CONFIG_CYZ_INTR */
                                )
                                free_irq(card->irq, card);
index af7c13ca949377da39751cb78df840b21de7ff32..abef1f7d84fefb03ef23ffc90417d173aea7ceef 100644 (file)
@@ -745,7 +745,7 @@ static int epca_carrier_raised(struct tty_port *port)
        return 0;
 }
 
-static void epca_raise_dtr_rts(struct tty_port *port)
+static void epca_dtr_rts(struct tty_port *port, int onoff)
 {
 }
 
@@ -925,7 +925,7 @@ static const struct tty_operations pc_ops = {
 
 static const struct tty_port_operations epca_port_ops = {
        .carrier_raised = epca_carrier_raised,
-       .raise_dtr_rts = epca_raise_dtr_rts,
+       .dtr_rts = epca_dtr_rts,
 };
 
 static int info_open(struct tty_struct *tty, struct file *filp)
@@ -1518,7 +1518,7 @@ static void doevent(int crd)
                if (event & MODEMCHG_IND) {
                        /* A modem signal change has been indicated */
                        ch->imodem = mstat;
-                       if (test_bit(ASYNC_CHECK_CD, &ch->port.flags)) {
+                       if (test_bit(ASYNCB_CHECK_CD, &ch->port.flags)) {
                                /* We are now receiving dcd */
                                if (mstat & ch->dcd)
                                        wake_up_interruptible(&ch->port.open_wait);
@@ -1765,9 +1765,9 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
                 * that the driver will wait on carrier detect.
                 */
                if (ts->c_cflag & CLOCAL)
-                       clear_bit(ASYNC_CHECK_CD, &ch->port.flags);
+                       clear_bit(ASYNCB_CHECK_CD, &ch->port.flags);
                else
-                       set_bit(ASYNC_CHECK_CD, &ch->port.flags);
+                       set_bit(ASYNCB_CHECK_CD, &ch->port.flags);
                mval = ch->m_dtr | ch->m_rts;
        } /* End CBAUD not detected */
        iflag = termios2digi_i(ch, ts->c_iflag);
@@ -2114,8 +2114,8 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file,
                        tty_wait_until_sent(tty, 0);
                } else {
                        /* ldisc lock already held in ioctl */
-                       if (tty->ldisc.ops->flush_buffer)
-                               tty->ldisc.ops->flush_buffer(tty);
+                       if (tty->ldisc->ops->flush_buffer)
+                               tty->ldisc->ops->flush_buffer(tty);
                }
                unlock_kernel();
                /* Fall Thru */
@@ -2244,7 +2244,8 @@ static void do_softint(struct work_struct *work)
                        if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
                                tty_hangup(tty);
                                wake_up_interruptible(&ch->port.open_wait);
-                               clear_bit(ASYNC_NORMAL_ACTIVE, &ch->port.flags);
+                               clear_bit(ASYNCB_NORMAL_ACTIVE,
+                                               &ch->port.flags);
                        }
                }
                tty_kref_put(tty);
index 340ba4f9dc54880bd6a3f7661ebba93d9c81733b..4a9f3492b9216142333f3fa2013542b4638b9c1e 100644 (file)
@@ -224,7 +224,7 @@ static void hpet_timer_set_irq(struct hpet_dev *devp)
                        break;
                }
 
-               gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE,
+               gsi = acpi_register_gsi(NULL, irq, ACPI_LEVEL_SENSITIVE,
                                        ACPI_ACTIVE_LOW);
                if (gsi > 0)
                        break;
@@ -939,7 +939,7 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
                irqp = &res->data.extended_irq;
 
                for (i = 0; i < irqp->interrupt_count; i++) {
-                       irq = acpi_register_gsi(irqp->interrupts[i],
+                       irq = acpi_register_gsi(NULL, irqp->interrupts[i],
                                      irqp->triggering, irqp->polarity);
                        if (irq < 0)
                                return AE_ERROR;
index 0061e18aff6045624e6fad0eaaa804f8f9d951e2..0d10b89218ed1da1818f47c643705f99d9dd3b55 100644 (file)
@@ -868,11 +868,11 @@ i2Input(i2ChanStrPtr pCh)
                amountToMove = count;
        }
        // Move the first block
-       pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY,
+       pCh->pTTY->ldisc->ops->receive_buf( pCh->pTTY,
                 &(pCh->Ibuf[stripIndex]), NULL, amountToMove );
        // If we needed to wrap, do the second data move
        if (count > amountToMove) {
-               pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY,
+               pCh->pTTY->ldisc->ops->receive_buf( pCh->pTTY,
                 pCh->Ibuf, NULL, count - amountToMove );
        }
        // Bump and wrap the stripIndex all at once by the amount of data read. This
index afd9247cf082d15e2cb6f1e8273c72fba9317ba5..517271c762e6b620b1323da302c5cd837985c626 100644 (file)
@@ -1315,8 +1315,8 @@ static inline void  isig(int sig, struct tty_struct *tty, int flush)
        if (tty->pgrp)
                kill_pgrp(tty->pgrp, sig, 1);
        if (flush || !L_NOFLSH(tty)) {
-               if ( tty->ldisc.ops->flush_buffer )  
-                       tty->ldisc.ops->flush_buffer(tty);
+               if ( tty->ldisc->ops->flush_buffer )  
+                       tty->ldisc->ops->flush_buffer(tty);
                i2InputFlush( tty->driver_data );
        }
 }
index a59eac584d1621b3e4824ca3e644d944a31266a6..4d745a89504f196cc545145ca4bd653c4927ad0b 100644 (file)
@@ -329,7 +329,7 @@ static inline void drop_rts(struct isi_port *port)
 
 /* card->lock MUST NOT be held */
 
-static void isicom_raise_dtr_rts(struct tty_port *port)
+static void isicom_dtr_rts(struct tty_port *port, int on)
 {
        struct isi_port *ip = container_of(port, struct isi_port, port);
        struct isi_board *card = ip->card;
@@ -339,10 +339,17 @@ static void isicom_raise_dtr_rts(struct tty_port *port)
        if (!lock_card(card))
                return;
 
-       outw(0x8000 | (channel << card->shift_count) | 0x02, base);
-       outw(0x0f04, base);
-       InterruptTheCard(base);
-       ip->status |= (ISI_DTR | ISI_RTS);
+       if (on) {
+               outw(0x8000 | (channel << card->shift_count) | 0x02, base);
+               outw(0x0f04, base);
+               InterruptTheCard(base);
+               ip->status |= (ISI_DTR | ISI_RTS);
+       } else {
+               outw(0x8000 | (channel << card->shift_count) | 0x02, base);
+               outw(0x0C04, base);
+               InterruptTheCard(base);
+               ip->status &= ~(ISI_DTR | ISI_RTS);
+       }
        unlock_card(card);
 }
 
@@ -1339,7 +1346,7 @@ static const struct tty_operations isicom_ops = {
 
 static const struct tty_port_operations isicom_port_ops = {
        .carrier_raised         = isicom_carrier_raised,
-       .raise_dtr_rts          = isicom_raise_dtr_rts,
+       .dtr_rts                = isicom_dtr_rts,
 };
 
 static int __devinit reset_card(struct pci_dev *pdev,
index fff19f7e29d25eac8c7cfbb4903638107dd8561c..e18800c400b10b60578b6fb9bb1d86a16dcbfd04 100644 (file)
@@ -1140,14 +1140,14 @@ static int stli_carrier_raised(struct tty_port *port)
        return (portp->sigs & TIOCM_CD) ? 1 : 0;
 }
 
-static void stli_raise_dtr_rts(struct tty_port *port)
+static void stli_dtr_rts(struct tty_port *port, int on)
 {
        struct stliport *portp = container_of(port, struct stliport, port);
        struct stlibrd *brdp = stli_brds[portp->brdnr];
-       stli_mkasysigs(&portp->asig, 1, 1);
+       stli_mkasysigs(&portp->asig, on, on);
        if (stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
                sizeof(asysigs_t), 0) < 0)
-                       printk(KERN_WARNING "istallion: dtr raise failed.\n");
+                       printk(KERN_WARNING "istallion: dtr set failed.\n");
 }
 
 
@@ -4417,7 +4417,7 @@ static const struct tty_operations stli_ops = {
 
 static const struct tty_port_operations stli_port_ops = {
        .carrier_raised = stli_carrier_raised,
-       .raise_dtr_rts = stli_raise_dtr_rts,
+       .dtr_rts = stli_dtr_rts,
 };
 
 /*****************************************************************************/
index 65e12bca657cfa0ba14f842ce6b442411f68bca6..f96d0bef855e3cda2507c698eb5cfdef85567c10 100644 (file)
@@ -694,9 +694,8 @@ static ssize_t read_zero(struct file * file, char __user * buf,
                written += chunk - unwritten;
                if (unwritten)
                        break;
-               /* Consider changing this to just 'signal_pending()' with lots of testing */
-               if (fatal_signal_pending(current))
-                       return written ? written : -EINTR;
+               if (signal_pending(current))
+                       return written ? written : -ERESTARTSYS;
                buf += chunk;
                count -= chunk;
                cond_resched();
index 4a4cab73d0be176aa640c9717bc7582231b39495..65b6ff2442c6df4edfd839b37752ded8340df9c9 100644 (file)
@@ -1184,6 +1184,11 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
                return -ENODEV;
        }
 
+       if (port % MAX_PORTS_PER_BOARD >= brd->numPorts) {
+               mutex_unlock(&moxa_openlock);
+               return -ENODEV;
+       }
+
        ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
        ch->port.count++;
        tty->driver_data = ch;
index 13f8871e5b2177bb844018f6543ca2e690e973b6..9533f43a30bb0e7bad9873acb85d25cf39e44625 100644 (file)
@@ -547,14 +547,18 @@ static int mxser_carrier_raised(struct tty_port *port)
        return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0;
 }
 
-static void mxser_raise_dtr_rts(struct tty_port *port)
+static void mxser_dtr_rts(struct tty_port *port, int on)
 {
        struct mxser_port *mp = container_of(port, struct mxser_port, port);
        unsigned long flags;
 
        spin_lock_irqsave(&mp->slock, flags);
-       outb(inb(mp->ioaddr + UART_MCR) |
-               UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR);
+       if (on)
+               outb(inb(mp->ioaddr + UART_MCR) |
+                       UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR);
+       else
+               outb(inb(mp->ioaddr + UART_MCR)&~(UART_MCR_DTR | UART_MCR_RTS),
+                       mp->ioaddr + UART_MCR);
        spin_unlock_irqrestore(&mp->slock, flags);
 }
 
@@ -2356,7 +2360,7 @@ static const struct tty_operations mxser_ops = {
 
 struct tty_port_operations mxser_port_ops = {
        .carrier_raised = mxser_carrier_raised,
-       .raise_dtr_rts = mxser_raise_dtr_rts,
+       .dtr_rts = mxser_dtr_rts,
 };
 
 /*
index bacb3e2872ae49cbc5668e6a402cb50fbf75a30b..461ece591a5bf98fbc0f979e03d75ac8f9cc6234 100644 (file)
@@ -342,8 +342,8 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
 #endif
        
        /* Flush any pending characters in the driver and discipline. */
-       if (tty->ldisc.ops->flush_buffer)
-               tty->ldisc.ops->flush_buffer(tty);
+       if (tty->ldisc->ops->flush_buffer)
+               tty->ldisc->ops->flush_buffer(tty);
 
        tty_driver_flush_buffer(tty);
                
index f6f0e4ec2b510dde6ca5079f6def074e34f6fdce..94a5d5020abcec935e08d6bc74180a249ea58423 100644 (file)
 #define ECHO_OP_SET_CANON_COL 0x81
 #define ECHO_OP_ERASE_TAB 0x82
 
-static inline unsigned char *alloc_buf(void)
-{
-       gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
-
-       if (PAGE_SIZE != N_TTY_BUF_SIZE)
-               return kmalloc(N_TTY_BUF_SIZE, prio);
-       else
-               return (unsigned char *)__get_free_page(prio);
-}
-
-static inline void free_buf(unsigned char *buf)
-{
-       if (PAGE_SIZE != N_TTY_BUF_SIZE)
-               kfree(buf);
-       else
-               free_page((unsigned long) buf);
-}
-
 static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
                               unsigned char __user *ptr)
 {
@@ -1558,11 +1540,11 @@ static void n_tty_close(struct tty_struct *tty)
 {
        n_tty_flush_buffer(tty);
        if (tty->read_buf) {
-               free_buf(tty->read_buf);
+               kfree(tty->read_buf);
                tty->read_buf = NULL;
        }
        if (tty->echo_buf) {
-               free_buf(tty->echo_buf);
+               kfree(tty->echo_buf);
                tty->echo_buf = NULL;
        }
 }
@@ -1584,17 +1566,16 @@ static int n_tty_open(struct tty_struct *tty)
 
        /* These are ugly. Currently a malloc failure here can panic */
        if (!tty->read_buf) {
-               tty->read_buf = alloc_buf();
+               tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
                if (!tty->read_buf)
                        return -ENOMEM;
        }
        if (!tty->echo_buf) {
-               tty->echo_buf = alloc_buf();
+               tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+
                if (!tty->echo_buf)
                        return -ENOMEM;
        }
-       memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
-       memset(tty->echo_buf, 0, N_TTY_BUF_SIZE);
        reset_buffer_flags(tty);
        tty->column = 0;
        n_tty_set_termios(tty, NULL);
index 19d79fc54461c592111fbce5d0e68e395e10dcd4..77b3648892249f494724bf2a6302bdfc9158c4c5 100644 (file)
@@ -383,7 +383,7 @@ static void async_mode(MGSLPC_INFO *info);
 static void tx_timeout(unsigned long context);
 
 static int carrier_raised(struct tty_port *port);
-static void raise_dtr_rts(struct tty_port *port);
+static void dtr_rts(struct tty_port *port, int onoff);
 
 #if SYNCLINK_GENERIC_HDLC
 #define dev_to_port(D) (dev_to_hdlc(D)->priv)
@@ -513,7 +513,7 @@ static void ldisc_receive_buf(struct tty_struct *tty,
 
 static const struct tty_port_operations mgslpc_port_ops = {
        .carrier_raised = carrier_raised,
-       .raise_dtr_rts = raise_dtr_rts
+       .dtr_rts = dtr_rts
 };
 
 static int mgslpc_probe(struct pcmcia_device *link)
@@ -2528,13 +2528,16 @@ static int carrier_raised(struct tty_port *port)
        return 0;
 }
 
-static void raise_dtr_rts(struct tty_port *port)
+static void dtr_rts(struct tty_port *port, int onoff)
 {
        MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
        unsigned long flags;
 
        spin_lock_irqsave(&info->lock,flags);
-       info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+       if (onoff)
+               info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+       else
+               info->serial_signals &= ~SerialSignal_RTS + SerialSignal_DTR;
        set_signals(info);
        spin_unlock_irqrestore(&info->lock,flags);
 }
index 31038a0052a2c3e007a4e792f2945ff015a7856e..5acd29e6e0430ee6bc16f3b4757a4fc76eb5cc06 100644 (file)
@@ -30,7 +30,6 @@
 
 #include <asm/system.h>
 
-/* These are global because they are accessed in tty_io.c */
 #ifdef CONFIG_UNIX98_PTYS
 static struct tty_driver *ptm_driver;
 static struct tty_driver *pts_driver;
@@ -111,7 +110,7 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf,
        c = to->receive_room;
        if (c > count)
                c = count;
-       to->ldisc.ops->receive_buf(to, buf, NULL, c);
+       to->ldisc->ops->receive_buf(to, buf, NULL, c);
 
        return c;
 }
@@ -149,11 +148,11 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
        int count;
 
        /* We should get the line discipline lock for "tty->link" */
-       if (!to || !to->ldisc.ops->chars_in_buffer)
+       if (!to || !to->ldisc->ops->chars_in_buffer)
                return 0;
 
        /* The ldisc must report 0 if no characters available to be read */
-       count = to->ldisc.ops->chars_in_buffer(to);
+       count = to->ldisc->ops->chars_in_buffer(to);
 
        if (tty->driver->subtype == PTY_TYPE_SLAVE)
                return count;
@@ -187,8 +186,8 @@ static void pty_flush_buffer(struct tty_struct *tty)
        if (!to)
                return;
 
-       if (to->ldisc.ops->flush_buffer)
-               to->ldisc.ops->flush_buffer(to);
+       if (to->ldisc->ops->flush_buffer)
+               to->ldisc->ops->flush_buffer(to);
 
        if (to->packet) {
                spin_lock_irqsave(&tty->ctrl_lock, flags);
index 20d90e6a6e50fb41dfdd2601b1ae6617c40a6070..db32f0e4c7dd48aaef0f1022627a4bebaded6f39 100644 (file)
@@ -71,7 +71,7 @@ static int raw_open(struct inode *inode, struct file *filp)
        err = bd_claim(bdev, raw_open);
        if (err)
                goto out1;
-       err = set_blocksize(bdev, bdev_hardsect_size(bdev));
+       err = set_blocksize(bdev, bdev_logical_block_size(bdev));
        if (err)
                goto out2;
        filp->f_flags |= O_DIRECT;
index f59fc5cea0673546fa03b0395a8d12b6f7872ff4..63d5b628477a72bbffb6cb8696a0a4b615ef5725 100644 (file)
@@ -872,11 +872,16 @@ static int carrier_raised(struct tty_port *port)
        return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0;
 }
 
-static void raise_dtr_rts(struct tty_port *port)
+static void dtr_rts(struct tty_port *port, int on)
 {
        struct r_port *info = container_of(port, struct r_port, port);
-       sSetDTR(&info->channel);
-       sSetRTS(&info->channel);
+       if (on) {
+               sSetDTR(&info->channel);
+               sSetRTS(&info->channel);
+       } else {
+               sClrDTR(&info->channel);
+               sClrRTS(&info->channel);
+       }
 }
 
 /*
@@ -934,7 +939,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
        /*
         * Info->count is now 1; so it's safe to sleep now.
         */
-       if (!test_bit(ASYNC_INITIALIZED, &port->flags)) {
+       if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
                cp = &info->channel;
                sSetRxTrigger(cp, TRIG_1);
                if (sGetChanStatus(cp) & CD_ACT)
@@ -958,7 +963,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
                sEnRxFIFO(cp);
                sEnTransmit(cp);
 
-               set_bit(ASYNC_INITIALIZED, &info->port.flags);
+               set_bit(ASYNCB_INITIALIZED, &info->port.flags);
 
                /*
                 * Set up the tty->alt_speed kludge
@@ -1641,7 +1646,7 @@ static int rp_write(struct tty_struct *tty,
        /*  Write remaining data into the port's xmit_buf */
        while (1) {
                /* Hung up ? */
-               if (!test_bit(ASYNC_NORMAL_ACTIVE, &info->port.flags))
+               if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags))
                        goto end;
                c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
                c = min(c, XMIT_BUF_SIZE - info->xmit_head);
@@ -2250,7 +2255,7 @@ static const struct tty_operations rocket_ops = {
 
 static const struct tty_port_operations rocket_port_ops = {
        .carrier_raised = carrier_raised,
-       .raise_dtr_rts = raise_dtr_rts,
+       .dtr_rts = dtr_rts,
 };
 
 /*
index cb8ca5698963017d03ff6ed625ec41f0d0a6c062..f97b9e8480645f85c34efb7bcbb41b3474e34d6c 100644 (file)
@@ -327,7 +327,7 @@ int paste_selection(struct tty_struct *tty)
                }
                count = sel_buffer_lth - pasted;
                count = min(count, tty->receive_room);
-               tty->ldisc.ops->receive_buf(tty, sel_buffer + pasted,
+               tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
                                                                NULL, count);
                pasted += count;
        }
index 2ad813a801dc391cc8bca62a4cc847b16ea0d4d1..53e504f41b2043fa89b4b9a83637fe31251d38ab 100644 (file)
@@ -772,11 +772,11 @@ static int stl_carrier_raised(struct tty_port *port)
        return (portp->sigs & TIOCM_CD) ? 1 : 0;
 }
 
-static void stl_raise_dtr_rts(struct tty_port *port)
+static void stl_dtr_rts(struct tty_port *port, int on)
 {
        struct stlport *portp = container_of(port, struct stlport, port);
        /* Takes brd_lock internally */
-       stl_setsignals(portp, 1, 1);
+       stl_setsignals(portp, on, on);
 }
 
 /*****************************************************************************/
@@ -2547,7 +2547,7 @@ static const struct tty_operations stl_ops = {
 
 static const struct tty_port_operations stl_port_ops = {
        .carrier_raised = stl_carrier_raised,
-       .raise_dtr_rts = stl_raise_dtr_rts,
+       .dtr_rts = stl_dtr_rts,
 };
 
 /*****************************************************************************/
index afd0b26ca05681210edd0cc0f22b01497eea3e37..afded3a2379c592082e85e373236addce5d9fcd3 100644 (file)
@@ -3247,13 +3247,16 @@ static int carrier_raised(struct tty_port *port)
        return (info->serial_signals & SerialSignal_DCD) ? 1 : 0;
 }
 
-static void raise_dtr_rts(struct tty_port *port)
+static void dtr_rts(struct tty_port *port, int on)
 {
        struct mgsl_struct *info = container_of(port, struct mgsl_struct, port);
        unsigned long flags;
 
        spin_lock_irqsave(&info->irq_spinlock,flags);
-       info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+       if (on)
+               info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+       else
+               info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
        usc_set_serial_signals(info);
        spin_unlock_irqrestore(&info->irq_spinlock,flags);
 }
@@ -4258,7 +4261,7 @@ static void mgsl_add_device( struct mgsl_struct *info )
 
 static const struct tty_port_operations mgsl_port_ops = {
        .carrier_raised = carrier_raised,
-       .raise_dtr_rts = raise_dtr_rts,
+       .dtr_rts = dtr_rts,
 };
 
 
index 5e256494686a8413734db27db5b9826069e36847..1386625fc4caae4bdf6a39e6835d0026b0e27ca7 100644 (file)
@@ -214,6 +214,7 @@ struct slgt_desc
 #define set_desc_next(a,b) (a).next   = cpu_to_le32((unsigned int)(b))
 #define set_desc_count(a,b)(a).count  = cpu_to_le16((unsigned short)(b))
 #define set_desc_eof(a,b)  (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0))
+#define set_desc_status(a, b) (a).status = cpu_to_le16((unsigned short)(b))
 #define desc_count(a)      (le16_to_cpu((a).count))
 #define desc_status(a)     (le16_to_cpu((a).status))
 #define desc_complete(a)   (le16_to_cpu((a).status) & BIT15)
@@ -297,6 +298,7 @@ struct slgt_info {
        u32 max_frame_size;       /* as set by device config */
 
        unsigned int rbuf_fill_level;
+       unsigned int rx_pio;
        unsigned int if_mode;
        unsigned int base_clock;
 
@@ -331,6 +333,8 @@ struct slgt_info {
        struct slgt_desc *rbufs;
        unsigned int rbuf_current;
        unsigned int rbuf_index;
+       unsigned int rbuf_fill_index;
+       unsigned short rbuf_fill_count;
 
        unsigned int tbuf_count;
        struct slgt_desc *tbufs;
@@ -2110,6 +2114,40 @@ static void ri_change(struct slgt_info *info, unsigned short status)
        info->pending_bh |= BH_STATUS;
 }
 
+static void isr_rxdata(struct slgt_info *info)
+{
+       unsigned int count = info->rbuf_fill_count;
+       unsigned int i = info->rbuf_fill_index;
+       unsigned short reg;
+
+       while (rd_reg16(info, SSR) & IRQ_RXDATA) {
+               reg = rd_reg16(info, RDR);
+               DBGISR(("isr_rxdata %s RDR=%04X\n", info->device_name, reg));
+               if (desc_complete(info->rbufs[i])) {
+                       /* all buffers full */
+                       rx_stop(info);
+                       info->rx_restart = 1;
+                       continue;
+               }
+               info->rbufs[i].buf[count++] = (unsigned char)reg;
+               /* async mode saves status byte to buffer for each data byte */
+               if (info->params.mode == MGSL_MODE_ASYNC)
+                       info->rbufs[i].buf[count++] = (unsigned char)(reg >> 8);
+               if (count == info->rbuf_fill_level || (reg & BIT10)) {
+                       /* buffer full or end of frame */
+                       set_desc_count(info->rbufs[i], count);
+                       set_desc_status(info->rbufs[i], BIT15 | (reg >> 8));
+                       info->rbuf_fill_count = count = 0;
+                       if (++i == info->rbuf_count)
+                               i = 0;
+                       info->pending_bh |= BH_RECEIVE;
+               }
+       }
+
+       info->rbuf_fill_index = i;
+       info->rbuf_fill_count = count;
+}
+
 static void isr_serial(struct slgt_info *info)
 {
        unsigned short status = rd_reg16(info, SSR);
@@ -2125,6 +2163,8 @@ static void isr_serial(struct slgt_info *info)
                        if (info->tx_count)
                                isr_txeom(info, status);
                }
+               if (info->rx_pio && (status & IRQ_RXDATA))
+                       isr_rxdata(info);
                if ((status & IRQ_RXBREAK) && (status & RXBREAK)) {
                        info->icount.brk++;
                        /* process break detection if tty control allows */
@@ -2141,7 +2181,8 @@ static void isr_serial(struct slgt_info *info)
        } else {
                if (status & (IRQ_TXIDLE + IRQ_TXUNDER))
                        isr_txeom(info, status);
-
+               if (info->rx_pio && (status & IRQ_RXDATA))
+                       isr_rxdata(info);
                if (status & IRQ_RXIDLE) {
                        if (status & RXIDLE)
                                info->icount.rxidle++;
@@ -2642,6 +2683,10 @@ static int rx_enable(struct slgt_info *info, int enable)
                        return -EINVAL;
                }
                info->rbuf_fill_level = rbuf_fill_level;
+               if (rbuf_fill_level < 128)
+                       info->rx_pio = 1; /* PIO mode */
+               else
+                       info->rx_pio = 0; /* DMA mode */
                rx_stop(info); /* restart receiver to use new fill level */
        }
 
@@ -3099,13 +3144,16 @@ static int carrier_raised(struct tty_port *port)
        return (info->signals & SerialSignal_DCD) ? 1 : 0;
 }
 
-static void raise_dtr_rts(struct tty_port *port)
+static void dtr_rts(struct tty_port *port, int on)
 {
        unsigned long flags;
        struct slgt_info *info = container_of(port, struct slgt_info, port);
 
        spin_lock_irqsave(&info->lock,flags);
-       info->signals |= SerialSignal_RTS + SerialSignal_DTR;
+       if (on)
+               info->signals |= SerialSignal_RTS + SerialSignal_DTR;
+       else
+               info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
        set_signals(info);
        spin_unlock_irqrestore(&info->lock,flags);
 }
@@ -3419,7 +3467,7 @@ static void add_device(struct slgt_info *info)
 
 static const struct tty_port_operations slgt_port_ops = {
        .carrier_raised = carrier_raised,
-       .raise_dtr_rts = raise_dtr_rts,
+       .dtr_rts = dtr_rts,
 };
 
 /*
@@ -3841,15 +3889,27 @@ static void rx_start(struct slgt_info *info)
        rdma_reset(info);
        reset_rbufs(info);
 
-       /* set 1st descriptor address */
-       wr_reg32(info, RDDAR, info->rbufs[0].pdesc);
-
-       if (info->params.mode != MGSL_MODE_ASYNC) {
-               /* enable rx DMA and DMA interrupt */
-               wr_reg32(info, RDCSR, (BIT2 + BIT0));
+       if (info->rx_pio) {
+               /* rx request when rx FIFO not empty */
+               wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) & ~BIT14));
+               slgt_irq_on(info, IRQ_RXDATA);
+               if (info->params.mode == MGSL_MODE_ASYNC) {
+                       /* enable saving of rx status */
+                       wr_reg32(info, RDCSR, BIT6);
+               }
        } else {
-               /* enable saving of rx status, rx DMA and DMA interrupt */
-               wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0));
+               /* rx request when rx FIFO half full */
+               wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT14));
+               /* set 1st descriptor address */
+               wr_reg32(info, RDDAR, info->rbufs[0].pdesc);
+
+               if (info->params.mode != MGSL_MODE_ASYNC) {
+                       /* enable rx DMA and DMA interrupt */
+                       wr_reg32(info, RDCSR, (BIT2 + BIT0));
+               } else {
+                       /* enable saving of rx status, rx DMA and DMA interrupt */
+                       wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0));
+               }
        }
 
        slgt_irq_on(info, IRQ_RXOVER);
@@ -4467,6 +4527,8 @@ static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last
 static void reset_rbufs(struct slgt_info *info)
 {
        free_rbufs(info, 0, info->rbuf_count - 1);
+       info->rbuf_fill_index = 0;
+       info->rbuf_fill_count = 0;
 }
 
 /*
index 26de60efe4b247162c3be863bb3a3c66d86d6c49..6f727e3c53ade1028d21cf11f364bdcc2fafbed9 100644 (file)
@@ -3277,13 +3277,16 @@ static int carrier_raised(struct tty_port *port)
        return (info->serial_signals & SerialSignal_DCD) ? 1 : 0;
 }
 
-static void raise_dtr_rts(struct tty_port *port)
+static void dtr_rts(struct tty_port *port, int on)
 {
        SLMP_INFO *info = container_of(port, SLMP_INFO, port);
        unsigned long flags;
 
        spin_lock_irqsave(&info->lock,flags);
-       info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+       if (on)
+               info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+       else
+               info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
        set_signals(info);
        spin_unlock_irqrestore(&info->lock,flags);
 }
@@ -3746,7 +3749,7 @@ static void add_device(SLMP_INFO *info)
 
 static const struct tty_port_operations port_ops = {
        .carrier_raised = carrier_raised,
-       .raise_dtr_rts = raise_dtr_rts,
+       .dtr_rts = dtr_rts,
 };
 
 /* Allocate and initialize a device instance structure
index 55ba6f142883f6de16cc0460b540bbc64b932738..ac16fbec72d03018998b63fea0dd517800c2929f 100644 (file)
@@ -29,10 +29,7 @@ static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
        buf = kmalloc(sizeof(*buf), GFP_KERNEL);
        if (!buf)
                goto err;
-       if (PAGE_SIZE != N_TTY_BUF_SIZE)
-               buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-       else
-               buf->data = (unsigned char *)__get_free_page(GFP_KERNEL);
+       buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
        if (!buf->data)
                goto err_buf;
        atomic_set(&buf->count, 1);
@@ -52,10 +49,7 @@ err:
 static void tty_audit_buf_free(struct tty_audit_buf *buf)
 {
        WARN_ON(buf->valid != 0);
-       if (PAGE_SIZE != N_TTY_BUF_SIZE)
-               kfree(buf->data);
-       else
-               free_page((unsigned long)buf->data);
+       kfree(buf->data);
        kfree(buf);
 }
 
index 66b99a2049e373cacca62d54d1d689daed2417e2..939e198d7670adfdad2068b4036a8d9348779444 100644 (file)
@@ -295,7 +295,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
        struct tty_driver *p, *res = NULL;
        int tty_line = 0;
        int len;
-       char *str;
+       char *str, *stp;
 
        for (str = name; *str; str++)
                if ((*str >= '0' && *str <= '9') || *str == ',')
@@ -311,13 +311,14 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
        list_for_each_entry(p, &tty_drivers, tty_drivers) {
                if (strncmp(name, p->name, len) != 0)
                        continue;
-               if (*str == ',')
-                       str++;
-               if (*str == '\0')
-                       str = NULL;
+               stp = str;
+               if (*stp == ',')
+                       stp++;
+               if (*stp == '\0')
+                       stp = NULL;
 
                if (tty_line >= 0 && tty_line <= p->num && p->ops &&
-                   p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) {
+                   p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
                        res = tty_driver_kref_get(p);
                        *line = tty_line;
                        break;
@@ -469,43 +470,6 @@ void tty_wakeup(struct tty_struct *tty)
 
 EXPORT_SYMBOL_GPL(tty_wakeup);
 
-/**
- *     tty_ldisc_flush -       flush line discipline queue
- *     @tty: tty
- *
- *     Flush the line discipline queue (if any) for this tty. If there
- *     is no line discipline active this is a no-op.
- */
-
-void tty_ldisc_flush(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld = tty_ldisc_ref(tty);
-       if (ld) {
-               if (ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               tty_ldisc_deref(ld);
-       }
-       tty_buffer_flush(tty);
-}
-
-EXPORT_SYMBOL_GPL(tty_ldisc_flush);
-
-/**
- *     tty_reset_termios       -       reset terminal state
- *     @tty: tty to reset
- *
- *     Restore a terminal to the driver default state
- */
-
-static void tty_reset_termios(struct tty_struct *tty)
-{
-       mutex_lock(&tty->termios_mutex);
-       *tty->termios = tty->driver->init_termios;
-       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
-       mutex_unlock(&tty->termios_mutex);
-}
-
 /**
  *     do_tty_hangup           -       actual handler for hangup events
  *     @work: tty device
@@ -535,7 +499,6 @@ static void do_tty_hangup(struct work_struct *work)
        struct file *cons_filp = NULL;
        struct file *filp, *f = NULL;
        struct task_struct *p;
-       struct tty_ldisc *ld;
        int    closecount = 0, n;
        unsigned long flags;
        int refs = 0;
@@ -566,40 +529,8 @@ static void do_tty_hangup(struct work_struct *work)
                filp->f_op = &hung_up_tty_fops;
        }
        file_list_unlock();
-       /*
-        * FIXME! What are the locking issues here? This may me overdoing
-        * things... This question is especially important now that we've
-        * removed the irqlock.
-        */
-       ld = tty_ldisc_ref(tty);
-       if (ld != NULL) {
-               /* We may have no line discipline at this point */
-               if (ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               tty_driver_flush_buffer(tty);
-               if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
-                   ld->ops->write_wakeup)
-                       ld->ops->write_wakeup(tty);
-               if (ld->ops->hangup)
-                       ld->ops->hangup(tty);
-       }
-       /*
-        * FIXME: Once we trust the LDISC code better we can wait here for
-        * ldisc completion and fix the driver call race
-        */
-       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.
-        */
-       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
-               tty_reset_termios(tty);
-       /* Defer ldisc switch */
-       /* tty_deferred_ldisc_switch(N_TTY);
 
-         This should get done automatically when the port closes and
-         tty_release is called */
+       tty_ldisc_hangup(tty);
 
        read_lock(&tasklist_lock);
        if (tty->session) {
@@ -628,12 +559,15 @@ static void do_tty_hangup(struct work_struct *work)
        read_unlock(&tasklist_lock);
 
        spin_lock_irqsave(&tty->ctrl_lock, flags);
-       tty->flags = 0;
+       clear_bit(TTY_THROTTLED, &tty->flags);
+       clear_bit(TTY_PUSH, &tty->flags);
+       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
        put_pid(tty->session);
        put_pid(tty->pgrp);
        tty->session = NULL;
        tty->pgrp = NULL;
        tty->ctrl_status = 0;
+       set_bit(TTY_HUPPED, &tty->flags);
        spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 
        /* Account for the p->signal references we killed */
@@ -659,10 +593,7 @@ static void do_tty_hangup(struct work_struct *work)
         * can't yet guarantee all that.
         */
        set_bit(TTY_HUPPED, &tty->flags);
-       if (ld) {
-               tty_ldisc_enable(tty);
-               tty_ldisc_deref(ld);
-       }
+       tty_ldisc_enable(tty);
        unlock_kernel();
        if (f)
                fput(f);
@@ -2480,6 +2411,24 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
        return tty->ops->tiocmset(tty, file, set, clear);
 }
 
+struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
+{
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_MASTER)
+               tty = tty->link;
+       return tty;
+}
+EXPORT_SYMBOL(tty_pair_get_tty);
+
+struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
+{
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_MASTER)
+           return tty;
+       return tty->link;
+}
+EXPORT_SYMBOL(tty_pair_get_pty);
+
 /*
  * Split this up, as gcc can choke on it otherwise..
  */
@@ -2495,11 +2444,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        if (tty_paranoia_check(tty, inode, "tty_ioctl"))
                return -EINVAL;
 
-       real_tty = tty;
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_MASTER)
-               real_tty = tty->link;
-
+       real_tty = tty_pair_get_tty(tty);
 
        /*
         * Factor out some common prep work
@@ -2555,7 +2500,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case TIOCGSID:
                return tiocgsid(tty, real_tty, p);
        case TIOCGETD:
-               return put_user(tty->ldisc.ops->num, (int __user *)p);
+               return put_user(tty->ldisc->ops->num, (int __user *)p);
        case TIOCSETD:
                return tiocsetd(tty, p);
        /*
@@ -2770,6 +2715,7 @@ void initialize_tty_struct(struct tty_struct *tty,
        tty->buf.head = tty->buf.tail = NULL;
        tty_buffer_init(tty);
        mutex_init(&tty->termios_mutex);
+       mutex_init(&tty->ldisc_mutex);
        init_waitqueue_head(&tty->write_wait);
        init_waitqueue_head(&tty->read_wait);
        INIT_WORK(&tty->hangup_work, do_tty_hangup);
index 6f4c7d0a53bf36bc6ff28afeadca4720704e459f..8116bb1c8f801c505816b0eec531bed441ff0842 100644 (file)
@@ -97,14 +97,19 @@ EXPORT_SYMBOL(tty_driver_flush_buffer);
  *     @tty: terminal
  *
  *     Indicate that a tty should stop transmitting data down the stack.
+ *     Takes the termios mutex to protect against parallel throttle/unthrottle
+ *     and also to ensure the driver can consistently reference its own
+ *     termios data at this point when implementing software flow control.
  */
 
 void tty_throttle(struct tty_struct *tty)
 {
+       mutex_lock(&tty->termios_mutex);
        /* check TTY_THROTTLED first so it indicates our state */
        if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
            tty->ops->throttle)
                tty->ops->throttle(tty);
+       mutex_unlock(&tty->termios_mutex);
 }
 EXPORT_SYMBOL(tty_throttle);
 
@@ -113,13 +118,21 @@ EXPORT_SYMBOL(tty_throttle);
  *     @tty: terminal
  *
  *     Indicate that a tty may continue transmitting data down the stack.
+ *     Takes the termios mutex to protect against parallel throttle/unthrottle
+ *     and also to ensure the driver can consistently reference its own
+ *     termios data at this point when implementing software flow control.
+ *
+ *     Drivers should however remember that the stack can issue a throttle,
+ *     then change flow control method, then unthrottle.
  */
 
 void tty_unthrottle(struct tty_struct *tty)
 {
+       mutex_lock(&tty->termios_mutex);
        if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
            tty->ops->unthrottle)
                tty->ops->unthrottle(tty);
+       mutex_unlock(&tty->termios_mutex);
 }
 EXPORT_SYMBOL(tty_unthrottle);
 
@@ -613,9 +626,25 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
        return 0;
 }
 
+static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
+{
+       mutex_lock(&tty->termios_mutex);
+       memcpy(kterm, tty->termios, sizeof(struct ktermios));
+       mutex_unlock(&tty->termios_mutex);
+}
+
+static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
+{
+       mutex_lock(&tty->termios_mutex);
+       memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
+       mutex_unlock(&tty->termios_mutex);
+}
+
 static int get_termio(struct tty_struct *tty, struct termio __user *termio)
 {
-       if (kernel_termios_to_user_termio(termio, tty->termios))
+       struct ktermios kterm;
+       copy_termios(tty, &kterm);
+       if (kernel_termios_to_user_termio(termio, &kterm))
                return -EFAULT;
        return 0;
 }
@@ -917,6 +946,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
        struct tty_struct *real_tty;
        void __user *p = (void __user *)arg;
        int ret = 0;
+       struct ktermios kterm;
+       struct termiox ktermx;
 
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
            tty->driver->subtype == PTY_TYPE_MASTER)
@@ -952,23 +983,20 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                return set_termios(real_tty, p, TERMIOS_OLD);
 #ifndef TCGETS2
        case TCGETS:
-               mutex_lock(&real_tty->termios_mutex);
-               if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
+               copy_termios(real_tty, &kterm);
+               if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
                        ret = -EFAULT;
-               mutex_unlock(&real_tty->termios_mutex);
                return ret;
 #else
        case TCGETS:
-               mutex_lock(&real_tty->termios_mutex);
-               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
+               copy_termios(real_tty, &kterm);
+               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
                        ret = -EFAULT;
-               mutex_unlock(&real_tty->termios_mutex);
                return ret;
        case TCGETS2:
-               mutex_lock(&real_tty->termios_mutex);
-               if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
+               copy_termios(real_tty, &kterm);
+               if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
                        ret = -EFAULT;
-               mutex_unlock(&real_tty->termios_mutex);
                return ret;
        case TCSETSF2:
                return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
@@ -987,34 +1015,36 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                return set_termios(real_tty, p, TERMIOS_TERMIO);
 #ifndef TCGETS2
        case TIOCGLCKTRMIOS:
-               mutex_lock(&real_tty->termios_mutex);
-               if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
+               copy_termios_locked(real_tty, &kterm);
+               if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
                        ret = -EFAULT;
-               mutex_unlock(&real_tty->termios_mutex);
                return ret;
        case TIOCSLCKTRMIOS:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               mutex_lock(&real_tty->termios_mutex);
-               if (user_termios_to_kernel_termios(real_tty->termios_locked,
+               copy_termios_locked(real_tty, &kterm);
+               if (user_termios_to_kernel_termios(&kterm,
                                               (struct termios __user *) arg))
-                       ret = -EFAULT;
+                       return -EFAULT;
+               mutex_lock(&real_tty->termios_mutex);
+               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
                mutex_unlock(&real_tty->termios_mutex);
-               return ret;
+               return 0;
 #else
        case TIOCGLCKTRMIOS:
-               mutex_lock(&real_tty->termios_mutex);
-               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
+               copy_termios_locked(real_tty, &kterm);
+               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
                        ret = -EFAULT;
-               mutex_unlock(&real_tty->termios_mutex);
                return ret;
        case TIOCSLCKTRMIOS:
                if (!capable(CAP_SYS_ADMIN))
-                       ret = -EPERM;
-               mutex_lock(&real_tty->termios_mutex);
-               if (user_termios_to_kernel_termios_1(real_tty->termios_locked,
+                       return -EPERM;
+               copy_termios_locked(real_tty, &kterm);
+               if (user_termios_to_kernel_termios_1(&kterm,
                                               (struct termios __user *) arg))
-                       ret = -EFAULT;
+                       return -EFAULT;
+               mutex_lock(&real_tty->termios_mutex);
+               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
                mutex_unlock(&real_tty->termios_mutex);
                return ret;
 #endif
@@ -1023,9 +1053,10 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                if (real_tty->termiox == NULL)
                        return -EINVAL;
                mutex_lock(&real_tty->termios_mutex);
-               if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox)))
-                       ret = -EFAULT;
+               memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
                mutex_unlock(&real_tty->termios_mutex);
+               if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
+                       ret = -EFAULT;
                return ret;
        case TCSETX:
                return set_termiox(real_tty, p, 0);
@@ -1035,10 +1066,9 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                return set_termiox(real_tty, p, TERMIOS_FLUSH);
 #endif         
        case TIOCGSOFTCAR:
-               mutex_lock(&real_tty->termios_mutex);
-               ret = put_user(C_CLOCAL(real_tty) ? 1 : 0,
+               copy_termios(real_tty, &kterm);
+               ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
                                                (int __user *)arg);
-               mutex_unlock(&real_tty->termios_mutex);
                return ret;
        case TIOCSSOFTCAR:
                if (get_user(arg, (unsigned int __user *) arg))
index f78f5b0127a88501ec0b21cf9d42c517209ad933..39c8f86dedd49c9e60ebe1e4e218225416bf0375 100644 (file)
@@ -115,19 +115,22 @@ EXPORT_SYMBOL(tty_unregister_ldisc);
 /**
  *     tty_ldisc_try_get       -       try and reference an ldisc
  *     @disc: ldisc number
- *     @ld: tty ldisc structure to complete
  *
  *     Attempt to open and lock a line discipline into place. Return
- *     the line discipline refcounted and assigned in ld. On an error
- *     report the error code back
+ *     the line discipline refcounted or an error.
  */
 
-static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
+static struct tty_ldisc *tty_ldisc_try_get(int disc)
 {
        unsigned long flags;
+       struct tty_ldisc *ld;
        struct tty_ldisc_ops *ldops;
        int err = -EINVAL;
-       
+
+       ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
+       if (ld == NULL)
+               return ERR_PTR(-ENOMEM);
+
        spin_lock_irqsave(&tty_ldisc_lock, flags);
        ld->ops = NULL;
        ldops = tty_ldiscs[disc];
@@ -140,17 +143,19 @@ static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
                        /* lock it */
                        ldops->refcount++;
                        ld->ops = ldops;
+                       ld->refcount = 0;
                        err = 0;
                }
        }
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-       return err;
+       if (err)
+               return ERR_PTR(err);
+       return ld;
 }
 
 /**
  *     tty_ldisc_get           -       take a reference to an ldisc
  *     @disc: ldisc number
- *     @ld: tty line discipline structure to use
  *
  *     Takes a reference to a line discipline. Deals with refcounts and
  *     module locking counts. Returns NULL if the discipline is not available.
@@ -161,52 +166,54 @@ static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
  *             takes tty_ldisc_lock to guard against ldisc races
  */
 
-static int tty_ldisc_get(int disc, struct tty_ldisc *ld)
+static struct tty_ldisc *tty_ldisc_get(int disc)
 {
-       int err;
+       struct tty_ldisc *ld;
 
        if (disc < N_TTY || disc >= NR_LDISCS)
-               return -EINVAL;
-       err = tty_ldisc_try_get(disc, ld);
-       if (err < 0) {
+               return ERR_PTR(-EINVAL);
+       ld = tty_ldisc_try_get(disc);
+       if (IS_ERR(ld)) {
                request_module("tty-ldisc-%d", disc);
-               err = tty_ldisc_try_get(disc, ld);
+               ld = tty_ldisc_try_get(disc);
        }
-       return err;
+       return ld;
 }
 
 /**
  *     tty_ldisc_put           -       drop ldisc reference
- *     @disc: ldisc number
+ *     @ld: ldisc
  *
  *     Drop a reference to a line discipline. Manage refcounts and
- *     module usage counts
+ *     module usage counts. Free the ldisc once the recount hits zero.
  *
  *     Locking:
  *             takes tty_ldisc_lock to guard against ldisc races
  */
 
-static void tty_ldisc_put(struct tty_ldisc_ops *ld)
+static void tty_ldisc_put(struct tty_ldisc *ld)
 {
        unsigned long flags;
-       int disc = ld->num;
+       int disc = ld->ops->num;
+       struct tty_ldisc_ops *ldo;
 
        BUG_ON(disc < N_TTY || disc >= NR_LDISCS);
 
        spin_lock_irqsave(&tty_ldisc_lock, flags);
-       ld = tty_ldiscs[disc];
-       BUG_ON(ld->refcount == 0);
-       ld->refcount--;
-       module_put(ld->owner);
+       ldo = tty_ldiscs[disc];
+       BUG_ON(ldo->refcount == 0);
+       ldo->refcount--;
+       module_put(ldo->owner);
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+       kfree(ld);
 }
 
-static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
+static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
 {
        return (*pos < NR_LDISCS) ? pos : NULL;
 }
 
-static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
+static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
 {
        (*pos)++;
        return (*pos < NR_LDISCS) ? pos : NULL;
@@ -219,12 +226,13 @@ static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
 static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
 {
        int i = *(loff_t *)v;
-       struct tty_ldisc ld;
-       
-       if (tty_ldisc_get(i, &ld) < 0)
+       struct tty_ldisc *ld;
+
+       ld = tty_ldisc_try_get(i);
+       if (IS_ERR(ld))
                return 0;
-       seq_printf(m, "%-10s %2d\n", ld.ops->name ? ld.ops->name : "???", i);
-       tty_ldisc_put(ld.ops);
+       seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i);
+       tty_ldisc_put(ld);
        return 0;
 }
 
@@ -263,8 +271,7 @@ const struct file_operations tty_ldiscs_proc_fops = {
 
 static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
 {
-       ld->refcount = 0;
-       tty->ldisc = *ld;
+       tty->ldisc = ld;
 }
 
 /**
@@ -286,7 +293,7 @@ static int tty_ldisc_try(struct tty_struct *tty)
        int ret = 0;
 
        spin_lock_irqsave(&tty_ldisc_lock, flags);
-       ld = &tty->ldisc;
+       ld = tty->ldisc;
        if (test_bit(TTY_LDISC, &tty->flags)) {
                ld->refcount++;
                ret = 1;
@@ -315,10 +322,9 @@ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
 {
        /* wait_event is a macro */
        wait_event(tty_ldisc_wait, tty_ldisc_try(tty));
-       WARN_ON(tty->ldisc.refcount == 0);
-       return &tty->ldisc;
+       WARN_ON(tty->ldisc->refcount == 0);
+       return tty->ldisc;
 }
-
 EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
 
 /**
@@ -335,10 +341,9 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
 struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
 {
        if (tty_ldisc_try(tty))
-               return &tty->ldisc;
+               return tty->ldisc;
        return NULL;
 }
-
 EXPORT_SYMBOL_GPL(tty_ldisc_ref);
 
 /**
@@ -366,7 +371,6 @@ void tty_ldisc_deref(struct tty_ldisc *ld)
                wake_up(&tty_ldisc_wait);
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 }
-
 EXPORT_SYMBOL_GPL(tty_ldisc_deref);
 
 /**
@@ -388,6 +392,26 @@ void tty_ldisc_enable(struct tty_struct *tty)
        wake_up(&tty_ldisc_wait);
 }
 
+/**
+ *     tty_ldisc_flush -       flush line discipline queue
+ *     @tty: tty
+ *
+ *     Flush the line discipline queue (if any) for this tty. If there
+ *     is no line discipline active this is a no-op.
+ */
+
+void tty_ldisc_flush(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld = tty_ldisc_ref(tty);
+       if (ld) {
+               if (ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_ldisc_deref(ld);
+       }
+       tty_buffer_flush(tty);
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_flush);
+
 /**
  *     tty_set_termios_ldisc           -       set ldisc field
  *     @tty: tty structure
@@ -407,6 +431,39 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
        mutex_unlock(&tty->termios_mutex);
 }
 
+/**
+ *     tty_ldisc_open          -       open a line discipline
+ *     @tty: tty we are opening the ldisc on
+ *     @ld: discipline to open
+ *
+ *     A helper opening method. Also a convenient debugging and check
+ *     point.
+ */
+
+static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+       WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
+       if (ld->ops->open)
+               return ld->ops->open(tty);
+       return 0;
+}
+
+/**
+ *     tty_ldisc_close         -       close a line discipline
+ *     @tty: tty we are opening the ldisc on
+ *     @ld: discipline to close
+ *
+ *     A helper close method. Also a convenient debugging and check
+ *     point.
+ */
+
+static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+       WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
+       clear_bit(TTY_LDISC_OPEN, &tty->flags);
+       if (ld->ops->close)
+               ld->ops->close(tty);
+}
 
 /**
  *     tty_ldisc_restore       -       helper for tty ldisc change
@@ -420,66 +477,136 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
 static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
 {
        char buf[64];
-       struct tty_ldisc new_ldisc;
+       struct tty_ldisc *new_ldisc;
+       int r;
 
        /* There is an outstanding reference here so this is safe */
-       tty_ldisc_get(old->ops->num, old);
+       old = tty_ldisc_get(old->ops->num);
+       WARN_ON(IS_ERR(old));
        tty_ldisc_assign(tty, old);
        tty_set_termios_ldisc(tty, old->ops->num);
-       if (old->ops->open && (old->ops->open(tty) < 0)) {
-               tty_ldisc_put(old->ops);
+       if (tty_ldisc_open(tty, old) < 0) {
+               tty_ldisc_put(old);
                /* This driver is always present */
-               if (tty_ldisc_get(N_TTY, &new_ldisc) < 0)
+               new_ldisc = tty_ldisc_get(N_TTY);
+               if (IS_ERR(new_ldisc))
                        panic("n_tty: get");
-               tty_ldisc_assign(tty, &new_ldisc);
+               tty_ldisc_assign(tty, new_ldisc);
                tty_set_termios_ldisc(tty, N_TTY);
-               if (new_ldisc.ops->open) {
-                       int r = new_ldisc.ops->open(tty);
-                               if (r < 0)
-                               panic("Couldn't open N_TTY ldisc for "
-                                     "%s --- error %d.",
-                                     tty_name(tty, buf), r);
-               }
+               r = tty_ldisc_open(tty, new_ldisc);
+               if (r < 0)
+                       panic("Couldn't open N_TTY ldisc for "
+                             "%s --- error %d.",
+                             tty_name(tty, buf), r);
        }
 }
 
+/**
+ *     tty_ldisc_halt          -       shut down the line discipline
+ *     @tty: tty device
+ *
+ *     Shut down the line discipline and work queue for this tty device.
+ *     The TTY_LDISC flag being cleared ensures no further references can
+ *     be obtained while the delayed work queue halt ensures that no more
+ *     data is fed to the ldisc.
+ *
+ *     In order to wait for any existing references to complete see
+ *     tty_ldisc_wait_idle.
+ */
+
+static int tty_ldisc_halt(struct tty_struct *tty)
+{
+       clear_bit(TTY_LDISC, &tty->flags);
+       return cancel_delayed_work(&tty->buf.work);
+}
+
+/**
+ *     tty_ldisc_wait_idle     -       wait for the ldisc to become idle
+ *     @tty: tty to wait for
+ *
+ *     Wait for the line discipline to become idle. The discipline must
+ *     have been halted for this to guarantee it remains idle.
+ *
+ *     tty_ldisc_lock protects the ref counts currently.
+ */
+
+static int tty_ldisc_wait_idle(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       while (tty->ldisc->refcount) {
+               spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+               if (wait_event_timeout(tty_ldisc_wait,
+                               tty->ldisc->refcount == 0, 5 * HZ) == 0)
+                       return -EBUSY;
+               spin_lock_irqsave(&tty_ldisc_lock, flags);
+       }
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+       return 0;
+}
+
 /**
  *     tty_set_ldisc           -       set line discipline
  *     @tty: the terminal to set
  *     @ldisc: the line discipline
  *
  *     Set the discipline of a tty line. Must be called from a process
- *     context.
+ *     context. The ldisc change logic has to protect itself against any
+ *     overlapping ldisc change (including on the other end of pty pairs),
+ *     the close of one side of a tty/pty pair, and eventually hangup.
  *
- *     Locking: takes tty_ldisc_lock.
- *              called functions take termios_mutex
+ *     Locking: takes tty_ldisc_lock, termios_mutex
  */
 
 int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 {
        int retval;
-       struct tty_ldisc o_ldisc, new_ldisc;
-       int work;
-       unsigned long flags;
+       struct tty_ldisc *o_ldisc, *new_ldisc;
+       int work, o_work = 0;
        struct tty_struct *o_tty;
 
-restart:
-       /* This is a bit ugly for now but means we can break the 'ldisc
-          is part of the tty struct' assumption later */
-       retval = tty_ldisc_get(ldisc, &new_ldisc);
-       if (retval)
-               return retval;
+       new_ldisc = tty_ldisc_get(ldisc);
+       if (IS_ERR(new_ldisc))
+               return PTR_ERR(new_ldisc);
+
+       /*
+        *      We need to look at the tty locking here for pty/tty pairs
+        *      when both sides try to change in parallel.
+        */
+
+       o_tty = tty->link;      /* o_tty is the pty side or NULL */
+
+
+       /*
+        *      Check the no-op case
+        */
+
+       if (tty->ldisc->ops->num == ldisc) {
+               tty_ldisc_put(new_ldisc);
+               return 0;
+       }
 
        /*
         *      Problem: What do we do if this blocks ?
+        *      We could deadlock here
         */
 
        tty_wait_until_sent(tty, 0);
 
-       if (tty->ldisc.ops->num == ldisc) {
-               tty_ldisc_put(new_ldisc.ops);
-               return 0;
+       mutex_lock(&tty->ldisc_mutex);
+
+       /*
+        *      We could be midstream of another ldisc change which has
+        *      dropped the lock during processing. If so we need to wait.
+        */
+
+       while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
+               mutex_unlock(&tty->ldisc_mutex);
+               wait_event(tty_ldisc_wait,
+                       test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
+               mutex_lock(&tty->ldisc_mutex);
        }
+       set_bit(TTY_LDISC_CHANGING, &tty->flags);
 
        /*
         *      No more input please, we are switching. The new ldisc
@@ -489,8 +616,6 @@ restart:
        tty->receive_room = 0;
 
        o_ldisc = tty->ldisc;
-       o_tty = tty->link;
-
        /*
         *      Make sure we don't change while someone holds a
         *      reference to the line discipline. The TTY_LDISC bit
@@ -501,108 +626,181 @@ restart:
         *      with a userspace app continually trying to use the tty in
         *      parallel to the change and re-referencing the tty.
         */
-       clear_bit(TTY_LDISC, &tty->flags);
-       if (o_tty)
-               clear_bit(TTY_LDISC, &o_tty->flags);
 
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) {
-               if (tty->ldisc.refcount) {
-                       /* Free the new ldisc we grabbed. Must drop the lock
-                          first. */
-                       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-                       tty_ldisc_put(o_ldisc.ops);
-                       /*
-                        * There are several reasons we may be busy, including
-                        * random momentary I/O traffic. We must therefore
-                        * retry. We could distinguish between blocking ops
-                        * and retries if we made tty_ldisc_wait() smarter.
-                        * That is up for discussion.
-                        */
-                       if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0)
-                               return -ERESTARTSYS;
-                       goto restart;
-               }
-               if (o_tty && o_tty->ldisc.refcount) {
-                       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-                       tty_ldisc_put(o_tty->ldisc.ops);
-                       if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0)
-                               return -ERESTARTSYS;
-                       goto restart;
-               }
-       }
-       /*
-        *      If the TTY_LDISC bit is set, then we are racing against
-        *      another ldisc change
-        */
-       if (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
-               struct tty_ldisc *ld;
-               spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-               tty_ldisc_put(new_ldisc.ops);
-               ld = tty_ldisc_ref_wait(tty);
-               tty_ldisc_deref(ld);
-               goto restart;
-       }
-       /*
-        *      This flag is used to avoid two parallel ldisc changes. Once
-        *      open and close are fine grained locked this may work better
-        *      as a mutex shared with the open/close/hup paths
-        */
-       set_bit(TTY_LDISC_CHANGING, &tty->flags);
+       work = tty_ldisc_halt(tty);
        if (o_tty)
-               set_bit(TTY_LDISC_CHANGING, &o_tty->flags);
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-       
-       /*
-        *      From this point on we know nobody has an ldisc
-        *      usage reference, nor can they obtain one until
-        *      we say so later on.
-        */
+               o_work = tty_ldisc_halt(o_tty);
 
-       work = cancel_delayed_work(&tty->buf.work);
        /*
-        * Wait for ->hangup_work and ->buf.work handlers to terminate
-        * MUST NOT hold locks here.
+        * Wait for ->hangup_work and ->buf.work handlers to terminate.
+        * We must drop the mutex here in case a hangup is also in process.
         */
+
+       mutex_unlock(&tty->ldisc_mutex);
+
        flush_scheduled_work();
+
+       /* Let any existing reference holders finish */
+       retval = tty_ldisc_wait_idle(tty);
+       if (retval < 0) {
+               clear_bit(TTY_LDISC_CHANGING, &tty->flags);
+               tty_ldisc_put(new_ldisc);
+               return retval;
+       }
+
+       mutex_lock(&tty->ldisc_mutex);
+       if (test_bit(TTY_HUPPED, &tty->flags)) {
+               /* We were raced by the hangup method. It will have stomped
+                  the ldisc data and closed the ldisc down */
+               clear_bit(TTY_LDISC_CHANGING, &tty->flags);
+               mutex_unlock(&tty->ldisc_mutex);
+               tty_ldisc_put(new_ldisc);
+               return -EIO;
+       }
+
        /* Shutdown the current discipline. */
-       if (o_ldisc.ops->close)
-               (o_ldisc.ops->close)(tty);
+       tty_ldisc_close(tty, o_ldisc);
 
        /* Now set up the new line discipline. */
-       tty_ldisc_assign(tty, &new_ldisc);
+       tty_ldisc_assign(tty, new_ldisc);
        tty_set_termios_ldisc(tty, ldisc);
-       if (new_ldisc.ops->open)
-               retval = (new_ldisc.ops->open)(tty);
+
+       retval = tty_ldisc_open(tty, new_ldisc);
        if (retval < 0) {
-               tty_ldisc_put(new_ldisc.ops);
-               tty_ldisc_restore(tty, &o_ldisc);
+               /* Back to the old one or N_TTY if we can't */
+               tty_ldisc_put(new_ldisc);
+               tty_ldisc_restore(tty, o_ldisc);
        }
+
        /* At this point we hold a reference to the new ldisc and a
           a reference to the old ldisc. If we ended up flipping back
           to the existing ldisc we have two references to it */
 
-       if (tty->ldisc.ops->num != o_ldisc.ops->num && tty->ops->set_ldisc)
+       if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc)
                tty->ops->set_ldisc(tty);
 
-       tty_ldisc_put(o_ldisc.ops);
+       tty_ldisc_put(o_ldisc);
 
        /*
-        *      Allow ldisc referencing to occur as soon as the driver
-        *      ldisc callback completes.
+        *      Allow ldisc referencing to occur again
         */
 
        tty_ldisc_enable(tty);
        if (o_tty)
                tty_ldisc_enable(o_tty);
 
-       /* Restart it in case no characters kick it off. Safe if
+       /* Restart the work queue in case no characters kick it off. Safe if
           already running */
        if (work)
                schedule_delayed_work(&tty->buf.work, 1);
+       if (o_work)
+               schedule_delayed_work(&o_tty->buf.work, 1);
+       mutex_unlock(&tty->ldisc_mutex);
        return retval;
 }
 
+/**
+ *     tty_reset_termios       -       reset terminal state
+ *     @tty: tty to reset
+ *
+ *     Restore a terminal to the driver default state.
+ */
+
+static void tty_reset_termios(struct tty_struct *tty)
+{
+       mutex_lock(&tty->termios_mutex);
+       *tty->termios = tty->driver->init_termios;
+       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+       mutex_unlock(&tty->termios_mutex);
+}
+
+
+/**
+ *     tty_ldisc_reinit        -       reinitialise the tty ldisc
+ *     @tty: tty to reinit
+ *
+ *     Switch the tty back to N_TTY line discipline and leave the
+ *     ldisc state closed
+ */
+
+static void tty_ldisc_reinit(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld;
+
+       tty_ldisc_close(tty, tty->ldisc);
+       tty_ldisc_put(tty->ldisc);
+       tty->ldisc = NULL;
+       /*
+        *      Switch the line discipline back
+        */
+       ld = tty_ldisc_get(N_TTY);
+       BUG_ON(IS_ERR(ld));
+       tty_ldisc_assign(tty, ld);
+       tty_set_termios_ldisc(tty, N_TTY);
+}
+
+/**
+ *     tty_ldisc_hangup                -       hangup ldisc reset
+ *     @tty: tty being hung up
+ *
+ *     Some tty devices reset their termios when they receive a hangup
+ *     event. In that situation we must also switch back to N_TTY properly
+ *     before we reset the termios data.
+ *
+ *     Locking: We can take the ldisc mutex as the rest of the code is
+ *     careful to allow for this.
+ *
+ *     In the pty pair case this occurs in the close() path of the
+ *     tty itself so we must be careful about locking rules.
+ */
+
+void tty_ldisc_hangup(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld;
+
+       /*
+        * FIXME! What are the locking issues here? This may me overdoing
+        * things... This question is especially important now that we've
+        * removed the irqlock.
+        */
+       ld = tty_ldisc_ref(tty);
+       if (ld != NULL) {
+               /* We may have no line discipline at this point */
+               if (ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_driver_flush_buffer(tty);
+               if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
+                   ld->ops->write_wakeup)
+                       ld->ops->write_wakeup(tty);
+               if (ld->ops->hangup)
+                       ld->ops->hangup(tty);
+               tty_ldisc_deref(ld);
+       }
+       /*
+        * FIXME: Once we trust the LDISC code better we can wait here for
+        * ldisc completion and fix the driver call race
+        */
+       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.
+        */
+       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
+               /* Avoid racing set_ldisc */
+               mutex_lock(&tty->ldisc_mutex);
+               /* Switch back to N_TTY */
+               tty_ldisc_reinit(tty);
+               /* At this point we have a closed ldisc and we want to
+                  reopen it. We could defer this to the next open but
+                  it means auditing a lot of other paths so this is a FIXME */
+               WARN_ON(tty_ldisc_open(tty, tty->ldisc));
+               tty_ldisc_enable(tty);
+               mutex_unlock(&tty->ldisc_mutex);
+               tty_reset_termios(tty);
+       }
+}
 
 /**
  *     tty_ldisc_setup                 -       open line discipline
@@ -610,24 +808,23 @@ restart:
  *     @o_tty: pair tty for pty/tty pairs
  *
  *     Called during the initial open of a tty/pty pair in order to set up the
- *     line discplines and bind them to the tty.
+ *     line disciplines and bind them to the tty. This has no locking issues
+ *     as the device isn't yet active.
  */
 
 int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
 {
-       struct tty_ldisc *ld = &tty->ldisc;
+       struct tty_ldisc *ld = tty->ldisc;
        int retval;
 
-       if (ld->ops->open) {
-               retval = (ld->ops->open)(tty);
-               if (retval)
-                       return retval;
-       }
-       if (o_tty && o_tty->ldisc.ops->open) {
-               retval = (o_tty->ldisc.ops->open)(o_tty);
+       retval = tty_ldisc_open(tty, ld);
+       if (retval)
+               return retval;
+
+       if (o_tty) {
+               retval = tty_ldisc_open(o_tty, o_tty->ldisc);
                if (retval) {
-                       if (ld->ops->close)
-                               (ld->ops->close)(tty);
+                       tty_ldisc_close(tty, ld);
                        return retval;
                }
                tty_ldisc_enable(o_tty);
@@ -635,32 +832,25 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
        tty_ldisc_enable(tty);
        return 0;
 }
-
 /**
  *     tty_ldisc_release               -       release line discipline
  *     @tty: tty being shut down
  *     @o_tty: pair tty for pty/tty pairs
  *
- *     Called during the final close of a tty/pty pair in order to shut down the
- *     line discpline layer.
+ *     Called during the final close of a tty/pty pair in order to shut down
+ *     the line discpline layer. On exit the ldisc assigned is N_TTY and the
+ *     ldisc has not been opened.
  */
 
 void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
 {
-       unsigned long flags;
-       struct tty_ldisc ld;
        /*
         * Prevent flush_to_ldisc() from rescheduling the work for later.  Then
         * kill any delayed work. As this is the final close it does not
         * race with the set_ldisc code path.
         */
-       clear_bit(TTY_LDISC, &tty->flags);
-       cancel_delayed_work(&tty->buf.work);
-
-       /*
-        * Wait for ->hangup_work and ->buf.work handlers to terminate
-        */
 
+       tty_ldisc_halt(tty);
        flush_scheduled_work();
 
        /*
@@ -668,38 +858,19 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
         * side waiters as the file is closing so user count on the file
         * side is zero.
         */
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       while (tty->ldisc.refcount) {
-               spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-               wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0);
-               spin_lock_irqsave(&tty_ldisc_lock, flags);
-       }
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+       tty_ldisc_wait_idle(tty);
+
        /*
         * Shutdown the current line discipline, and reset it to N_TTY.
         *
         * FIXME: this MUST get fixed for the new reflocking
         */
-       if (tty->ldisc.ops->close)
-               (tty->ldisc.ops->close)(tty);
-       tty_ldisc_put(tty->ldisc.ops);
 
-       /*
-        *      Switch the line discipline back
-        */
-       WARN_ON(tty_ldisc_get(N_TTY, &ld));
-       tty_ldisc_assign(tty, &ld);
-       tty_set_termios_ldisc(tty, N_TTY);
-       if (o_tty) {
-               /* FIXME: could o_tty be in setldisc here ? */
-               clear_bit(TTY_LDISC, &o_tty->flags);
-               if (o_tty->ldisc.ops->close)
-                       (o_tty->ldisc.ops->close)(o_tty);
-               tty_ldisc_put(o_tty->ldisc.ops);
-               WARN_ON(tty_ldisc_get(N_TTY, &ld));
-               tty_ldisc_assign(o_tty, &ld);
-               tty_set_termios_ldisc(o_tty, N_TTY);
-       }
+       tty_ldisc_reinit(tty);
+       /* This will need doing differently if we need to lock */
+       if (o_tty)
+               tty_ldisc_release(o_tty, NULL);
 }
 
 /**
@@ -712,10 +883,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
 
 void tty_ldisc_init(struct tty_struct *tty)
 {
-       struct tty_ldisc ld;
-       if (tty_ldisc_get(N_TTY, &ld) < 0)
+       struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
+       if (IS_ERR(ld))
                panic("n_tty: init_tty");
-       tty_ldisc_assign(tty, &ld);
+       tty_ldisc_assign(tty, ld);
 }
 
 void tty_ldisc_begin(void)
index 9b8004c72686a45f6ea577f1cd342e001dbbfa49..62dadfc95e341078ef42a284366cef37dbac6432 100644 (file)
@@ -137,7 +137,7 @@ int tty_port_carrier_raised(struct tty_port *port)
 EXPORT_SYMBOL(tty_port_carrier_raised);
 
 /**
- *     tty_port_raise_dtr_rts  -       Riase DTR/RTS
+ *     tty_port_raise_dtr_rts  -       Raise DTR/RTS
  *     @port: tty port
  *
  *     Wrapper for the DTR/RTS raise logic. For the moment this is used
@@ -147,11 +147,27 @@ EXPORT_SYMBOL(tty_port_carrier_raised);
 
 void tty_port_raise_dtr_rts(struct tty_port *port)
 {
-       if (port->ops->raise_dtr_rts)
-               port->ops->raise_dtr_rts(port);
+       if (port->ops->dtr_rts)
+               port->ops->dtr_rts(port, 1);
 }
 EXPORT_SYMBOL(tty_port_raise_dtr_rts);
 
+/**
+ *     tty_port_lower_dtr_rts  -       Lower DTR/RTS
+ *     @port: tty port
+ *
+ *     Wrapper for the DTR/RTS raise logic. For the moment this is used
+ *     to hide some internal details. This will eventually become entirely
+ *     internal to the tty port.
+ */
+
+void tty_port_lower_dtr_rts(struct tty_port *port)
+{
+       if (port->ops->dtr_rts)
+               port->ops->dtr_rts(port, 0);
+}
+EXPORT_SYMBOL(tty_port_lower_dtr_rts);
+
 /**
  *     tty_port_block_til_ready        -       Waiting logic for tty open
  *     @port: the tty port being opened
@@ -167,7 +183,7 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts);
  *             - port flags and counts
  *
  *     The passed tty_port must implement the carrier_raised method if it can
- *     do carrier detect and the raise_dtr_rts method if it supports software
+ *     do carrier detect and the dtr_rts method if it supports software
  *     management of these lines. Note that the dtr/rts raise is done each
  *     iteration as a hangup may have previously dropped them while we wait.
  */
@@ -182,7 +198,8 @@ int tty_port_block_til_ready(struct tty_port *port,
 
        /* block if port is in the process of being closed */
        if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-               interruptible_sleep_on(&port->close_wait);
+               wait_event_interruptible(port->close_wait,
+                               !(port->flags & ASYNC_CLOSING));
                if (port->flags & ASYNC_HUP_NOTIFY)
                        return -EAGAIN;
                else
@@ -205,7 +222,6 @@ int tty_port_block_til_ready(struct tty_port *port,
           before the next open may complete */
 
        retval = 0;
-       add_wait_queue(&port->open_wait, &wait);
 
        /* The port lock protects the port counts */
        spin_lock_irqsave(&port->lock, flags);
@@ -219,7 +235,7 @@ int tty_port_block_til_ready(struct tty_port *port,
                if (tty->termios->c_cflag & CBAUD)
                        tty_port_raise_dtr_rts(port);
 
-               set_current_state(TASK_INTERRUPTIBLE);
+               prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
                /* Check for a hangup or uninitialised port. Return accordingly */
                if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
                        if (port->flags & ASYNC_HUP_NOTIFY)
@@ -240,8 +256,7 @@ int tty_port_block_til_ready(struct tty_port *port,
                }
                schedule();
        }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&port->open_wait, &wait);
+       finish_wait(&port->open_wait, &wait);
 
        /* Update counts. A parallel hangup will have set count to zero and
           we must not mess that up further */
@@ -292,6 +307,17 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
        if (port->flags & ASYNC_INITIALIZED &&
                        port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
                tty_wait_until_sent(tty, port->closing_wait);
+       if (port->drain_delay) {
+               unsigned int bps = tty_get_baud_rate(tty);
+               long timeout;
+
+               if (bps > 1200)
+                       timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps,
+                                                               HZ / 10);
+               else
+                       timeout = 2 * HZ;
+               schedule_timeout_interruptible(timeout);
+       }
        return 1;
 }
 EXPORT_SYMBOL(tty_port_close_start);
@@ -302,6 +328,9 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
 
        tty_ldisc_flush(tty);
 
+       if (tty->termios->c_cflag & HUPCL)
+               tty_port_lower_dtr_rts(port);
+
        spin_lock_irqsave(&port->lock, flags);
        tty->closing = 0;
 
index 1efb2879a94f48b30b3f100608328cd3a46b8bd9..eef216f7f61d6a80ac57f435003b92f45b2b5579 100644 (file)
@@ -3,3 +3,5 @@ obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o
 obj-$(CONFIG_X86_PM_TIMER)     += acpi_pm.o
 obj-$(CONFIG_SCx200HR_TIMER)   += scx200_hrt.o
 obj-$(CONFIG_SH_TIMER_CMT)     += sh_cmt.o
+obj-$(CONFIG_SH_TIMER_MTU2)    += sh_mtu2.o
+obj-$(CONFIG_SH_TIMER_TMU)     += sh_tmu.o
index 1c92c39a53aaa61cfd1e2a1add78776f4c167a84..cf56a2af5fe111b3cbb15db3a1edb27a23d207de 100644 (file)
@@ -18,7 +18,6 @@
  */
 
 #include <linux/init.h>
-#include <linux/bootmem.h>
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
@@ -29,7 +28,7 @@
 #include <linux/err.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
-#include <linux/sh_cmt.h>
+#include <linux/sh_timer.h>
 
 struct sh_cmt_priv {
        void __iomem *mapbase;
@@ -47,6 +46,7 @@ struct sh_cmt_priv {
        unsigned long rate;
        spinlock_t lock;
        struct clock_event_device ced;
+       struct clocksource cs;
        unsigned long total_cycles;
 };
 
@@ -59,7 +59,7 @@ static DEFINE_SPINLOCK(sh_cmt_lock);
 
 static inline unsigned long sh_cmt_read(struct sh_cmt_priv *p, int reg_nr)
 {
-       struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
+       struct sh_timer_config *cfg = p->pdev->dev.platform_data;
        void __iomem *base = p->mapbase;
        unsigned long offs;
 
@@ -83,7 +83,7 @@ static inline unsigned long sh_cmt_read(struct sh_cmt_priv *p, int reg_nr)
 static inline void sh_cmt_write(struct sh_cmt_priv *p, int reg_nr,
                                unsigned long value)
 {
-       struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
+       struct sh_timer_config *cfg = p->pdev->dev.platform_data;
        void __iomem *base = p->mapbase;
        unsigned long offs;
 
@@ -110,23 +110,28 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p,
                                        int *has_wrapped)
 {
        unsigned long v1, v2, v3;
+       int o1, o2;
+
+       o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit;
 
        /* Make sure the timer value is stable. Stolen from acpi_pm.c */
        do {
+               o2 = o1;
                v1 = sh_cmt_read(p, CMCNT);
                v2 = sh_cmt_read(p, CMCNT);
                v3 = sh_cmt_read(p, CMCNT);
-       } while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
-                         || (v3 > v1 && v3 < v2)));
+               o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit;
+       } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
+                         || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
 
-       *has_wrapped = sh_cmt_read(p, CMCSR) & p->overflow_bit;
+       *has_wrapped = o1;
        return v2;
 }
 
 
 static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start)
 {
-       struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
+       struct sh_timer_config *cfg = p->pdev->dev.platform_data;
        unsigned long flags, value;
 
        /* start stop register shared by multiple timer channels */
@@ -144,7 +149,7 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start)
 
 static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
 {
-       struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
+       struct sh_timer_config *cfg = p->pdev->dev.platform_data;
        int ret;
 
        /* enable clock */
@@ -153,16 +158,18 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
                pr_err("sh_cmt: cannot enable clock \"%s\"\n", cfg->clk);
                return ret;
        }
-       *rate = clk_get_rate(p->clk) / 8;
 
        /* make sure channel is disabled */
        sh_cmt_start_stop_ch(p, 0);
 
        /* configure channel, periodic mode and maximum timeout */
-       if (p->width == 16)
-               sh_cmt_write(p, CMCSR, 0);
-       else
+       if (p->width == 16) {
+               *rate = clk_get_rate(p->clk) / 512;
+               sh_cmt_write(p, CMCSR, 0x43);
+       } else {
+               *rate = clk_get_rate(p->clk) / 8;
                sh_cmt_write(p, CMCSR, 0x01a4);
+       }
 
        sh_cmt_write(p, CMCOR, 0xffffffff);
        sh_cmt_write(p, CMCNT, 0);
@@ -376,6 +383,68 @@ static void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag)
        spin_unlock_irqrestore(&p->lock, flags);
 }
 
+static struct sh_cmt_priv *cs_to_sh_cmt(struct clocksource *cs)
+{
+       return container_of(cs, struct sh_cmt_priv, cs);
+}
+
+static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
+{
+       struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
+       unsigned long flags, raw;
+       unsigned long value;
+       int has_wrapped;
+
+       spin_lock_irqsave(&p->lock, flags);
+       value = p->total_cycles;
+       raw = sh_cmt_get_counter(p, &has_wrapped);
+
+       if (unlikely(has_wrapped))
+               raw += p->match_value;
+       spin_unlock_irqrestore(&p->lock, flags);
+
+       return value + raw;
+}
+
+static int sh_cmt_clocksource_enable(struct clocksource *cs)
+{
+       struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
+       int ret;
+
+       p->total_cycles = 0;
+
+       ret = sh_cmt_start(p, FLAG_CLOCKSOURCE);
+       if (ret)
+               return ret;
+
+       /* TODO: calculate good shift from rate and counter bit width */
+       cs->shift = 0;
+       cs->mult = clocksource_hz2mult(p->rate, cs->shift);
+       return 0;
+}
+
+static void sh_cmt_clocksource_disable(struct clocksource *cs)
+{
+       sh_cmt_stop(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE);
+}
+
+static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
+                                      char *name, unsigned long rating)
+{
+       struct clocksource *cs = &p->cs;
+
+       cs->name = name;
+       cs->rating = rating;
+       cs->read = sh_cmt_clocksource_read;
+       cs->enable = sh_cmt_clocksource_enable;
+       cs->disable = sh_cmt_clocksource_disable;
+       cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
+       cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
+       pr_info("sh_cmt: %s used as clock source\n", cs->name);
+       clocksource_register(cs);
+       return 0;
+}
+
 static struct sh_cmt_priv *ced_to_sh_cmt(struct clock_event_device *ced)
 {
        return container_of(ced, struct sh_cmt_priv, ced);
@@ -468,9 +537,9 @@ static void sh_cmt_register_clockevent(struct sh_cmt_priv *p,
        clockevents_register_device(ced);
 }
 
-int sh_cmt_register(struct sh_cmt_priv *p, char *name,
-                   unsigned long clockevent_rating,
-                   unsigned long clocksource_rating)
+static int sh_cmt_register(struct sh_cmt_priv *p, char *name,
+                          unsigned long clockevent_rating,
+                          unsigned long clocksource_rating)
 {
        if (p->width == (sizeof(p->max_match_value) * 8))
                p->max_match_value = ~0;
@@ -483,12 +552,15 @@ int sh_cmt_register(struct sh_cmt_priv *p, char *name,
        if (clockevent_rating)
                sh_cmt_register_clockevent(p, name, clockevent_rating);
 
+       if (clocksource_rating)
+               sh_cmt_register_clocksource(p, name, clocksource_rating);
+
        return 0;
 }
 
 static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
 {
-       struct sh_cmt_config *cfg = pdev->dev.platform_data;
+       struct sh_timer_config *cfg = pdev->dev.platform_data;
        struct resource *res;
        int irq, ret;
        ret = -ENXIO;
@@ -545,7 +617,7 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
        if (resource_size(res) == 6) {
                p->width = 16;
                p->overflow_bit = 0x80;
-               p->clear_bits = ~0xc0;
+               p->clear_bits = ~0x80;
        } else {
                p->width = 32;
                p->overflow_bit = 0x8000;
@@ -566,8 +638,14 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
 static int __devinit sh_cmt_probe(struct platform_device *pdev)
 {
        struct sh_cmt_priv *p = platform_get_drvdata(pdev);
+       struct sh_timer_config *cfg = pdev->dev.platform_data;
        int ret;
 
+       if (p) {
+               pr_info("sh_cmt: %s kept as earlytimer\n", cfg->name);
+               return 0;
+       }
+
        p = kmalloc(sizeof(*p), GFP_KERNEL);
        if (p == NULL) {
                dev_err(&pdev->dev, "failed to allocate driver data\n");
@@ -577,7 +655,6 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
        ret = sh_cmt_setup(p, pdev);
        if (ret) {
                kfree(p);
-
                platform_set_drvdata(pdev, NULL);
        }
        return ret;
@@ -606,6 +683,7 @@ static void __exit sh_cmt_exit(void)
        platform_driver_unregister(&sh_cmt_device_driver);
 }
 
+early_platform_init("earlytimer", &sh_cmt_device_driver);
 module_init(sh_cmt_init);
 module_exit(sh_cmt_exit);
 
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c
new file mode 100644 (file)
index 0000000..d1ae754
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * SuperH Timer Support - MTU2
+ *
+ *  Copyright (C) 2009 Magnus Damm
+ *
+ * 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
+ *
+ * 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 <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/clockchips.h>
+#include <linux/sh_timer.h>
+
+struct sh_mtu2_priv {
+       void __iomem *mapbase;
+       struct clk *clk;
+       struct irqaction irqaction;
+       struct platform_device *pdev;
+       unsigned long rate;
+       unsigned long periodic;
+       struct clock_event_device ced;
+};
+
+static DEFINE_SPINLOCK(sh_mtu2_lock);
+
+#define TSTR -1 /* shared register */
+#define TCR  0 /* channel register */
+#define TMDR 1 /* channel register */
+#define TIOR 2 /* channel register */
+#define TIER 3 /* channel register */
+#define TSR  4 /* channel register */
+#define TCNT 5 /* channel register */
+#define TGR  6 /* channel register */
+
+static unsigned long mtu2_reg_offs[] = {
+       [TCR] = 0,
+       [TMDR] = 1,
+       [TIOR] = 2,
+       [TIER] = 4,
+       [TSR] = 5,
+       [TCNT] = 6,
+       [TGR] = 8,
+};
+
+static inline unsigned long sh_mtu2_read(struct sh_mtu2_priv *p, int reg_nr)
+{
+       struct sh_timer_config *cfg = p->pdev->dev.platform_data;
+       void __iomem *base = p->mapbase;
+       unsigned long offs;
+
+       if (reg_nr == TSTR)
+               return ioread8(base + cfg->channel_offset);
+
+       offs = mtu2_reg_offs[reg_nr];
+
+       if ((reg_nr == TCNT) || (reg_nr == TGR))
+               return ioread16(base + offs);
+       else
+               return ioread8(base + offs);
+}
+
+static inline void sh_mtu2_write(struct sh_mtu2_priv *p, int reg_nr,
+                               unsigned long value)
+{
+       struct sh_timer_config *cfg = p->pdev->dev.platform_data;
+       void __iomem *base = p->mapbase;
+       unsigned long offs;
+
+       if (reg_nr == TSTR) {
+               iowrite8(value, base + cfg->channel_offset);
+               return;
+       }
+
+       offs = mtu2_reg_offs[reg_nr];
+
+       if ((reg_nr == TCNT) || (reg_nr == TGR))
+               iowrite16(value, base + offs);
+       else
+               iowrite8(value, base + offs);
+}
+
+static void sh_mtu2_start_stop_ch(struct sh_mtu2_priv *p, int start)
+{
+       struct sh_timer_config *cfg = p->pdev->dev.platform_data;
+       unsigned long flags, value;
+
+       /* start stop register shared by multiple timer channels */
+       spin_lock_irqsave(&sh_mtu2_lock, flags);
+       value = sh_mtu2_read(p, TSTR);
+
+       if (start)
+               value |= 1 << cfg->timer_bit;
+       else
+               value &= ~(1 << cfg->timer_bit);
+
+       sh_mtu2_write(p, TSTR, value);
+       spin_unlock_irqrestore(&sh_mtu2_lock, flags);
+}
+
+static int sh_mtu2_enable(struct sh_mtu2_priv *p)
+{
+       struct sh_timer_config *cfg = p->pdev->dev.platform_data;
+       int ret;
+
+       /* enable clock */
+       ret = clk_enable(p->clk);
+       if (ret) {
+               pr_err("sh_mtu2: cannot enable clock \"%s\"\n", cfg->clk);
+               return ret;
+       }
+
+       /* make sure channel is disabled */
+       sh_mtu2_start_stop_ch(p, 0);
+
+       p->rate = clk_get_rate(p->clk) / 64;
+       p->periodic = (p->rate + HZ/2) / HZ;
+
+       /* "Periodic Counter Operation" */
+       sh_mtu2_write(p, TCR, 0x23); /* TGRA clear, divide clock by 64 */
+       sh_mtu2_write(p, TIOR, 0);
+       sh_mtu2_write(p, TGR, p->periodic);
+       sh_mtu2_write(p, TCNT, 0);
+       sh_mtu2_write(p, TMDR, 0);
+       sh_mtu2_write(p, TIER, 0x01);
+
+       /* enable channel */
+       sh_mtu2_start_stop_ch(p, 1);
+
+       return 0;
+}
+
+static void sh_mtu2_disable(struct sh_mtu2_priv *p)
+{
+       /* disable channel */
+       sh_mtu2_start_stop_ch(p, 0);
+
+       /* stop clock */
+       clk_disable(p->clk);
+}
+
+static irqreturn_t sh_mtu2_interrupt(int irq, void *dev_id)
+{
+       struct sh_mtu2_priv *p = dev_id;
+
+       /* acknowledge interrupt */
+       sh_mtu2_read(p, TSR);
+       sh_mtu2_write(p, TSR, 0xfe);
+
+       /* notify clockevent layer */
+       p->ced.event_handler(&p->ced);
+       return IRQ_HANDLED;
+}
+
+static struct sh_mtu2_priv *ced_to_sh_mtu2(struct clock_event_device *ced)
+{
+       return container_of(ced, struct sh_mtu2_priv, ced);
+}
+
+static void sh_mtu2_clock_event_mode(enum clock_event_mode mode,
+                                   struct clock_event_device *ced)
+{
+       struct sh_mtu2_priv *p = ced_to_sh_mtu2(ced);
+       int disabled = 0;
+
+       /* deal with old setting first */
+       switch (ced->mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               sh_mtu2_disable(p);
+               disabled = 1;
+               break;
+       default:
+               break;
+       }
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               pr_info("sh_mtu2: %s used for periodic clock events\n",
+                       ced->name);
+               sh_mtu2_enable(p);
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+               if (!disabled)
+                       sh_mtu2_disable(p);
+               break;
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       default:
+               break;
+       }
+}
+
+static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p,
+                                      char *name, unsigned long rating)
+{
+       struct clock_event_device *ced = &p->ced;
+       int ret;
+
+       memset(ced, 0, sizeof(*ced));
+
+       ced->name = name;
+       ced->features = CLOCK_EVT_FEAT_PERIODIC;
+       ced->rating = rating;
+       ced->cpumask = cpumask_of(0);
+       ced->set_mode = sh_mtu2_clock_event_mode;
+
+       ret = setup_irq(p->irqaction.irq, &p->irqaction);
+       if (ret) {
+               pr_err("sh_mtu2: failed to request irq %d\n",
+                      p->irqaction.irq);
+               return;
+       }
+
+       pr_info("sh_mtu2: %s used for clock events\n", ced->name);
+       clockevents_register_device(ced);
+}
+
+static int sh_mtu2_register(struct sh_mtu2_priv *p, char *name,
+                           unsigned long clockevent_rating)
+{
+       if (clockevent_rating)
+               sh_mtu2_register_clockevent(p, name, clockevent_rating);
+
+       return 0;
+}
+
+static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
+{
+       struct sh_timer_config *cfg = pdev->dev.platform_data;
+       struct resource *res;
+       int irq, ret;
+       ret = -ENXIO;
+
+       memset(p, 0, sizeof(*p));
+       p->pdev = pdev;
+
+       if (!cfg) {
+               dev_err(&p->pdev->dev, "missing platform data\n");
+               goto err0;
+       }
+
+       platform_set_drvdata(pdev, p);
+
+       res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&p->pdev->dev, "failed to get I/O memory\n");
+               goto err0;
+       }
+
+       irq = platform_get_irq(p->pdev, 0);
+       if (irq < 0) {
+               dev_err(&p->pdev->dev, "failed to get irq\n");
+               goto err0;
+       }
+
+       /* map memory, let mapbase point to our channel */
+       p->mapbase = ioremap_nocache(res->start, resource_size(res));
+       if (p->mapbase == NULL) {
+               pr_err("sh_mtu2: failed to remap I/O memory\n");
+               goto err0;
+       }
+
+       /* setup data for setup_irq() (too early for request_irq()) */
+       p->irqaction.name = cfg->name;
+       p->irqaction.handler = sh_mtu2_interrupt;
+       p->irqaction.dev_id = p;
+       p->irqaction.irq = irq;
+       p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
+       p->irqaction.mask = CPU_MASK_NONE;
+
+       /* get hold of clock */
+       p->clk = clk_get(&p->pdev->dev, cfg->clk);
+       if (IS_ERR(p->clk)) {
+               pr_err("sh_mtu2: cannot get clock \"%s\"\n", cfg->clk);
+               ret = PTR_ERR(p->clk);
+               goto err1;
+       }
+
+       return sh_mtu2_register(p, cfg->name, cfg->clockevent_rating);
+ err1:
+       iounmap(p->mapbase);
+ err0:
+       return ret;
+}
+
+static int __devinit sh_mtu2_probe(struct platform_device *pdev)
+{
+       struct sh_mtu2_priv *p = platform_get_drvdata(pdev);
+       struct sh_timer_config *cfg = pdev->dev.platform_data;
+       int ret;
+
+       if (p) {
+               pr_info("sh_mtu2: %s kept as earlytimer\n", cfg->name);
+               return 0;
+       }
+
+       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       if (p == NULL) {
+               dev_err(&pdev->dev, "failed to allocate driver data\n");
+               return -ENOMEM;
+       }
+
+       ret = sh_mtu2_setup(p, pdev);
+       if (ret) {
+               kfree(p);
+               platform_set_drvdata(pdev, NULL);
+       }
+       return ret;
+}
+
+static int __devexit sh_mtu2_remove(struct platform_device *pdev)
+{
+       return -EBUSY; /* cannot unregister clockevent */
+}
+
+static struct platform_driver sh_mtu2_device_driver = {
+       .probe          = sh_mtu2_probe,
+       .remove         = __devexit_p(sh_mtu2_remove),
+       .driver         = {
+               .name   = "sh_mtu2",
+       }
+};
+
+static int __init sh_mtu2_init(void)
+{
+       return platform_driver_register(&sh_mtu2_device_driver);
+}
+
+static void __exit sh_mtu2_exit(void)
+{
+       platform_driver_unregister(&sh_mtu2_device_driver);
+}
+
+early_platform_init("earlytimer", &sh_mtu2_device_driver);
+module_init(sh_mtu2_init);
+module_exit(sh_mtu2_exit);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("SuperH MTU2 Timer Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
new file mode 100644 (file)
index 0000000..d6ea439
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * SuperH Timer Support - TMU
+ *
+ *  Copyright (C) 2009 Magnus Damm
+ *
+ * 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
+ *
+ * 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 <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/sh_timer.h>
+
+struct sh_tmu_priv {
+       void __iomem *mapbase;
+       struct clk *clk;
+       struct irqaction irqaction;
+       struct platform_device *pdev;
+       unsigned long rate;
+       unsigned long periodic;
+       struct clock_event_device ced;
+       struct clocksource cs;
+};
+
+static DEFINE_SPINLOCK(sh_tmu_lock);
+
+#define TSTR -1 /* shared register */
+#define TCOR  0 /* channel register */
+#define TCNT 1 /* channel register */
+#define TCR 2 /* channel register */
+
+static inline unsigned long sh_tmu_read(struct sh_tmu_priv *p, int reg_nr)
+{
+       struct sh_timer_config *cfg = p->pdev->dev.platform_data;
+       void __iomem *base = p->mapbase;
+       unsigned long offs;
+
+       if (reg_nr == TSTR)
+               return ioread8(base - cfg->channel_offset);
+
+       offs = reg_nr << 2;
+
+       if (reg_nr == TCR)
+               return ioread16(base + offs);
+       else
+               return ioread32(base + offs);
+}
+
+static inline void sh_tmu_write(struct sh_tmu_priv *p, int reg_nr,
+                               unsigned long value)
+{
+       struct sh_timer_config *cfg = p->pdev->dev.platform_data;
+       void __iomem *base = p->mapbase;
+       unsigned long offs;
+
+       if (reg_nr == TSTR) {
+               iowrite8(value, base - cfg->channel_offset);
+               return;
+       }
+
+       offs = reg_nr << 2;
+
+       if (reg_nr == TCR)
+               iowrite16(value, base + offs);
+       else
+               iowrite32(value, base + offs);
+}
+
+static void sh_tmu_start_stop_ch(struct sh_tmu_priv *p, int start)
+{
+       struct sh_timer_config *cfg = p->pdev->dev.platform_data;
+       unsigned long flags, value;
+
+       /* start stop register shared by multiple timer channels */
+       spin_lock_irqsave(&sh_tmu_lock, flags);
+       value = sh_tmu_read(p, TSTR);
+
+       if (start)
+               value |= 1 << cfg->timer_bit;
+       else
+               value &= ~(1 << cfg->timer_bit);
+
+       sh_tmu_write(p, TSTR, value);
+       spin_unlock_irqrestore(&sh_tmu_lock, flags);
+}
+
+static int sh_tmu_enable(struct sh_tmu_priv *p)
+{
+       struct sh_timer_config *cfg = p->pdev->dev.platform_data;
+       int ret;
+
+       /* enable clock */
+       ret = clk_enable(p->clk);
+       if (ret) {
+               pr_err("sh_tmu: cannot enable clock \"%s\"\n", cfg->clk);
+               return ret;
+       }
+
+       /* make sure channel is disabled */
+       sh_tmu_start_stop_ch(p, 0);
+
+       /* maximum timeout */
+       sh_tmu_write(p, TCOR, 0xffffffff);
+       sh_tmu_write(p, TCNT, 0xffffffff);
+
+       /* configure channel to parent clock / 4, irq off */
+       p->rate = clk_get_rate(p->clk) / 4;
+       sh_tmu_write(p, TCR, 0x0000);
+
+       /* enable channel */
+       sh_tmu_start_stop_ch(p, 1);
+
+       return 0;
+}
+
+static void sh_tmu_disable(struct sh_tmu_priv *p)
+{
+       /* disable channel */
+       sh_tmu_start_stop_ch(p, 0);
+
+       /* stop clock */
+       clk_disable(p->clk);
+}
+
+static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta,
+                           int periodic)
+{
+       /* stop timer */
+       sh_tmu_start_stop_ch(p, 0);
+
+       /* acknowledge interrupt */
+       sh_tmu_read(p, TCR);
+
+       /* enable interrupt */
+       sh_tmu_write(p, TCR, 0x0020);
+
+       /* reload delta value in case of periodic timer */
+       if (periodic)
+               sh_tmu_write(p, TCOR, delta);
+       else
+               sh_tmu_write(p, TCOR, 0);
+
+       sh_tmu_write(p, TCNT, delta);
+
+       /* start timer */
+       sh_tmu_start_stop_ch(p, 1);
+}
+
+static irqreturn_t sh_tmu_interrupt(int irq, void *dev_id)
+{
+       struct sh_tmu_priv *p = dev_id;
+
+       /* disable or acknowledge interrupt */
+       if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT)
+               sh_tmu_write(p, TCR, 0x0000);
+       else
+               sh_tmu_write(p, TCR, 0x0020);
+
+       /* notify clockevent layer */
+       p->ced.event_handler(&p->ced);
+       return IRQ_HANDLED;
+}
+
+static struct sh_tmu_priv *cs_to_sh_tmu(struct clocksource *cs)
+{
+       return container_of(cs, struct sh_tmu_priv, cs);
+}
+
+static cycle_t sh_tmu_clocksource_read(struct clocksource *cs)
+{
+       struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
+
+       return sh_tmu_read(p, TCNT) ^ 0xffffffff;
+}
+
+static int sh_tmu_clocksource_enable(struct clocksource *cs)
+{
+       struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
+       int ret;
+
+       ret = sh_tmu_enable(p);
+       if (ret)
+               return ret;
+
+       /* TODO: calculate good shift from rate and counter bit width */
+       cs->shift = 10;
+       cs->mult = clocksource_hz2mult(p->rate, cs->shift);
+       return 0;
+}
+
+static void sh_tmu_clocksource_disable(struct clocksource *cs)
+{
+       sh_tmu_disable(cs_to_sh_tmu(cs));
+}
+
+static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
+                                      char *name, unsigned long rating)
+{
+       struct clocksource *cs = &p->cs;
+
+       cs->name = name;
+       cs->rating = rating;
+       cs->read = sh_tmu_clocksource_read;
+       cs->enable = sh_tmu_clocksource_enable;
+       cs->disable = sh_tmu_clocksource_disable;
+       cs->mask = CLOCKSOURCE_MASK(32);
+       cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
+       pr_info("sh_tmu: %s used as clock source\n", cs->name);
+       clocksource_register(cs);
+       return 0;
+}
+
+static struct sh_tmu_priv *ced_to_sh_tmu(struct clock_event_device *ced)
+{
+       return container_of(ced, struct sh_tmu_priv, ced);
+}
+
+static void sh_tmu_clock_event_start(struct sh_tmu_priv *p, int periodic)
+{
+       struct clock_event_device *ced = &p->ced;
+
+       sh_tmu_enable(p);
+
+       /* TODO: calculate good shift from rate and counter bit width */
+
+       ced->shift = 32;
+       ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift);
+       ced->max_delta_ns = clockevent_delta2ns(0xffffffff, ced);
+       ced->min_delta_ns = 5000;
+
+       if (periodic) {
+               p->periodic = (p->rate + HZ/2) / HZ;
+               sh_tmu_set_next(p, p->periodic, 1);
+       }
+}
+
+static void sh_tmu_clock_event_mode(enum clock_event_mode mode,
+                                   struct clock_event_device *ced)
+{
+       struct sh_tmu_priv *p = ced_to_sh_tmu(ced);
+       int disabled = 0;
+
+       /* deal with old setting first */
+       switch (ced->mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+       case CLOCK_EVT_MODE_ONESHOT:
+               sh_tmu_disable(p);
+               disabled = 1;
+               break;
+       default:
+               break;
+       }
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               pr_info("sh_tmu: %s used for periodic clock events\n",
+                       ced->name);
+               sh_tmu_clock_event_start(p, 1);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               pr_info("sh_tmu: %s used for oneshot clock events\n",
+                       ced->name);
+               sh_tmu_clock_event_start(p, 0);
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+               if (!disabled)
+                       sh_tmu_disable(p);
+               break;
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       default:
+               break;
+       }
+}
+
+static int sh_tmu_clock_event_next(unsigned long delta,
+                                  struct clock_event_device *ced)
+{
+       struct sh_tmu_priv *p = ced_to_sh_tmu(ced);
+
+       BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
+
+       /* program new delta value */
+       sh_tmu_set_next(p, delta, 0);
+       return 0;
+}
+
+static void sh_tmu_register_clockevent(struct sh_tmu_priv *p,
+                                      char *name, unsigned long rating)
+{
+       struct clock_event_device *ced = &p->ced;
+       int ret;
+
+       memset(ced, 0, sizeof(*ced));
+
+       ced->name = name;
+       ced->features = CLOCK_EVT_FEAT_PERIODIC;
+       ced->features |= CLOCK_EVT_FEAT_ONESHOT;
+       ced->rating = rating;
+       ced->cpumask = cpumask_of(0);
+       ced->set_next_event = sh_tmu_clock_event_next;
+       ced->set_mode = sh_tmu_clock_event_mode;
+
+       ret = setup_irq(p->irqaction.irq, &p->irqaction);
+       if (ret) {
+               pr_err("sh_tmu: failed to request irq %d\n",
+                      p->irqaction.irq);
+               return;
+       }
+
+       pr_info("sh_tmu: %s used for clock events\n", ced->name);
+       clockevents_register_device(ced);
+}
+
+static int sh_tmu_register(struct sh_tmu_priv *p, char *name,
+                   unsigned long clockevent_rating,
+                   unsigned long clocksource_rating)
+{
+       if (clockevent_rating)
+               sh_tmu_register_clockevent(p, name, clockevent_rating);
+       else if (clocksource_rating)
+               sh_tmu_register_clocksource(p, name, clocksource_rating);
+
+       return 0;
+}
+
+static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
+{
+       struct sh_timer_config *cfg = pdev->dev.platform_data;
+       struct resource *res;
+       int irq, ret;
+       ret = -ENXIO;
+
+       memset(p, 0, sizeof(*p));
+       p->pdev = pdev;
+
+       if (!cfg) {
+               dev_err(&p->pdev->dev, "missing platform data\n");
+               goto err0;
+       }
+
+       platform_set_drvdata(pdev, p);
+
+       res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&p->pdev->dev, "failed to get I/O memory\n");
+               goto err0;
+       }
+
+       irq = platform_get_irq(p->pdev, 0);
+       if (irq < 0) {
+               dev_err(&p->pdev->dev, "failed to get irq\n");
+               goto err0;
+       }
+
+       /* map memory, let mapbase point to our channel */
+       p->mapbase = ioremap_nocache(res->start, resource_size(res));
+       if (p->mapbase == NULL) {
+               pr_err("sh_tmu: failed to remap I/O memory\n");
+               goto err0;
+       }
+
+       /* setup data for setup_irq() (too early for request_irq()) */
+       p->irqaction.name = cfg->name;
+       p->irqaction.handler = sh_tmu_interrupt;
+       p->irqaction.dev_id = p;
+       p->irqaction.irq = irq;
+       p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
+       p->irqaction.mask = CPU_MASK_NONE;
+
+       /* get hold of clock */
+       p->clk = clk_get(&p->pdev->dev, cfg->clk);
+       if (IS_ERR(p->clk)) {
+               pr_err("sh_tmu: cannot get clock \"%s\"\n", cfg->clk);
+               ret = PTR_ERR(p->clk);
+               goto err1;
+       }
+
+       return sh_tmu_register(p, cfg->name,
+                              cfg->clockevent_rating,
+                              cfg->clocksource_rating);
+ err1:
+       iounmap(p->mapbase);
+ err0:
+       return ret;
+}
+
+static int __devinit sh_tmu_probe(struct platform_device *pdev)
+{
+       struct sh_tmu_priv *p = platform_get_drvdata(pdev);
+       struct sh_timer_config *cfg = pdev->dev.platform_data;
+       int ret;
+
+       if (p) {
+               pr_info("sh_tmu: %s kept as earlytimer\n", cfg->name);
+               return 0;
+       }
+
+       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       if (p == NULL) {
+               dev_err(&pdev->dev, "failed to allocate driver data\n");
+               return -ENOMEM;
+       }
+
+       ret = sh_tmu_setup(p, pdev);
+       if (ret) {
+               kfree(p);
+               platform_set_drvdata(pdev, NULL);
+       }
+       return ret;
+}
+
+static int __devexit sh_tmu_remove(struct platform_device *pdev)
+{
+       return -EBUSY; /* cannot unregister clockevent and clocksource */
+}
+
+static struct platform_driver sh_tmu_device_driver = {
+       .probe          = sh_tmu_probe,
+       .remove         = __devexit_p(sh_tmu_remove),
+       .driver         = {
+               .name   = "sh_tmu",
+       }
+};
+
+static int __init sh_tmu_init(void)
+{
+       return platform_driver_register(&sh_tmu_device_driver);
+}
+
+static void __exit sh_tmu_exit(void)
+{
+       platform_driver_unregister(&sh_tmu_device_driver);
+}
+
+early_platform_init("earlytimer", &sh_tmu_device_driver);
+module_init(sh_tmu_init);
+module_exit(sh_tmu_exit);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("SuperH TMU Timer Driver");
+MODULE_LICENSE("GPL v2");
index 956982f8739b372d05c1f3dec73ad4735884b0e0..ab4f3592a11c58bcf48137afa6fedb5030cca8d3 100644 (file)
@@ -49,7 +49,6 @@ config EDAC_DEBUG_VERBOSE
 
 config EDAC_MM_EDAC
        tristate "Main Memory EDAC (Error Detection And Correction) reporting"
-       default y
        help
          Some systems are able to detect and correct errors in main
          memory.  EDAC can report statistics on memory error
@@ -58,6 +57,31 @@ config EDAC_MM_EDAC
          occurred so that a particular failing memory module can be
          replaced.  If unsure, select 'Y'.
 
+config EDAC_AMD64
+       tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h"
+       depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI
+       help
+         Support for error detection and correction on the AMD 64
+         Families of Memory Controllers (K8, F10h and F11h)
+
+config EDAC_AMD64_ERROR_INJECTION
+       bool "Sysfs Error Injection facilities"
+       depends on EDAC_AMD64
+       help
+         Recent Opterons (Family 10h and later) provide for Memory Error
+         Injection into the ECC detection circuits. The amd64_edac module
+         allows the operator/user to inject Uncorrectable and Correctable
+         errors into DRAM.
+
+         When enabled, in each of the respective memory controller directories
+         (/sys/devices/system/edac/mc/mcX), there are 3 input files:
+
+         - inject_section (0..3, 16-byte section of 64-byte cacheline),
+         - inject_word (0..8, 16-bit word of 16-byte section),
+         - inject_ecc_vector (hex ecc vector: select bits of inject word)
+
+         In addition, there are two control files, inject_read and inject_write,
+         which trigger the DRAM ECC Read and Write respectively.
 
 config EDAC_AMD76X
        tristate "AMD 76x (760, 762, 768)"
index 59076819135d2bca280f0b60ead4a1160177d549..633dc5604ee32e1d49acf2a7b9057b5c6e0a7e1f 100644 (file)
@@ -30,6 +30,13 @@ obj-$(CONFIG_EDAC_I3000)             += i3000_edac.o
 obj-$(CONFIG_EDAC_X38)                 += x38_edac.o
 obj-$(CONFIG_EDAC_I82860)              += i82860_edac.o
 obj-$(CONFIG_EDAC_R82600)              += r82600_edac.o
+
+amd64_edac_mod-y :=  amd64_edac_err_types.o amd64_edac.o
+amd64_edac_mod-$(CONFIG_EDAC_DEBUG) += amd64_edac_dbg.o
+amd64_edac_mod-$(CONFIG_EDAC_AMD64_ERROR_INJECTION) += amd64_edac_inj.o
+
+obj-$(CONFIG_EDAC_AMD64)               += amd64_edac_mod.o
+
 obj-$(CONFIG_EDAC_PASEMI)              += pasemi_edac.o
 obj-$(CONFIG_EDAC_MPC85XX)             += mpc85xx_edac.o
 obj-$(CONFIG_EDAC_MV64X60)             += mv64x60_edac.o
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
new file mode 100644 (file)
index 0000000..c36bf40
--- /dev/null
@@ -0,0 +1,3354 @@
+#include "amd64_edac.h"
+#include <asm/k8.h>
+
+static struct edac_pci_ctl_info *amd64_ctl_pci;
+
+static int report_gart_errors;
+module_param(report_gart_errors, int, 0644);
+
+/*
+ * Set by command line parameter. If BIOS has enabled the ECC, this override is
+ * cleared to prevent re-enabling the hardware by this driver.
+ */
+static int ecc_enable_override;
+module_param(ecc_enable_override, int, 0644);
+
+/* Lookup table for all possible MC control instances */
+struct amd64_pvt;
+static struct mem_ctl_info *mci_lookup[MAX_NUMNODES];
+static struct amd64_pvt *pvt_lookup[MAX_NUMNODES];
+
+/*
+ * Memory scrubber control interface. For K8, memory scrubbing is handled by
+ * hardware and can involve L2 cache, dcache as well as the main memory. With
+ * F10, this is extended to L3 cache scrubbing on CPU models sporting that
+ * functionality.
+ *
+ * This causes the "units" for the scrubbing speed to vary from 64 byte blocks
+ * (dram) over to cache lines. This is nasty, so we will use bandwidth in
+ * bytes/sec for the setting.
+ *
+ * Currently, we only do dram scrubbing. If the scrubbing is done in software on
+ * other archs, we might not have access to the caches directly.
+ */
+
+/*
+ * scan the scrub rate mapping table for a close or matching bandwidth value to
+ * issue. If requested is too big, then use last maximum value found.
+ */
+static int amd64_search_set_scrub_rate(struct pci_dev *ctl, u32 new_bw,
+                                      u32 min_scrubrate)
+{
+       u32 scrubval;
+       int i;
+
+       /*
+        * map the configured rate (new_bw) to a value specific to the AMD64
+        * memory controller and apply to register. Search for the first
+        * bandwidth entry that is greater or equal than the setting requested
+        * and program that. If at last entry, turn off DRAM scrubbing.
+        */
+       for (i = 0; i < ARRAY_SIZE(scrubrates); i++) {
+               /*
+                * skip scrub rates which aren't recommended
+                * (see F10 BKDG, F3x58)
+                */
+               if (scrubrates[i].scrubval < min_scrubrate)
+                       continue;
+
+               if (scrubrates[i].bandwidth <= new_bw)
+                       break;
+
+               /*
+                * if no suitable bandwidth found, turn off DRAM scrubbing
+                * entirely by falling back to the last element in the
+                * scrubrates array.
+                */
+       }
+
+       scrubval = scrubrates[i].scrubval;
+       if (scrubval)
+               edac_printk(KERN_DEBUG, EDAC_MC,
+                           "Setting scrub rate bandwidth: %u\n",
+                           scrubrates[i].bandwidth);
+       else
+               edac_printk(KERN_DEBUG, EDAC_MC, "Turning scrubbing off.\n");
+
+       pci_write_bits32(ctl, K8_SCRCTRL, scrubval, 0x001F);
+
+       return 0;
+}
+
+static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 *bandwidth)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       u32 min_scrubrate = 0x0;
+
+       switch (boot_cpu_data.x86) {
+       case 0xf:
+               min_scrubrate = K8_MIN_SCRUB_RATE_BITS;
+               break;
+       case 0x10:
+               min_scrubrate = F10_MIN_SCRUB_RATE_BITS;
+               break;
+       case 0x11:
+               min_scrubrate = F11_MIN_SCRUB_RATE_BITS;
+               break;
+
+       default:
+               amd64_printk(KERN_ERR, "Unsupported family!\n");
+               break;
+       }
+       return amd64_search_set_scrub_rate(pvt->misc_f3_ctl, *bandwidth,
+                       min_scrubrate);
+}
+
+static int amd64_get_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       u32 scrubval = 0;
+       int status = -1, i, ret = 0;
+
+       ret = pci_read_config_dword(pvt->misc_f3_ctl, K8_SCRCTRL, &scrubval);
+       if (ret)
+               debugf0("Reading K8_SCRCTRL failed\n");
+
+       scrubval = scrubval & 0x001F;
+
+       edac_printk(KERN_DEBUG, EDAC_MC,
+                   "pci-read, sdram scrub control value: %d \n", scrubval);
+
+       for (i = 0; ARRAY_SIZE(scrubrates); i++) {
+               if (scrubrates[i].scrubval == scrubval) {
+                       *bw = scrubrates[i].bandwidth;
+                       status = 0;
+                       break;
+               }
+       }
+
+       return status;
+}
+
+/* Map from a CSROW entry to the mask entry that operates on it */
+static inline u32 amd64_map_to_dcs_mask(struct amd64_pvt *pvt, int csrow)
+{
+       return csrow >> (pvt->num_dcsm >> 3);
+}
+
+/* return the 'base' address the i'th CS entry of the 'dct' DRAM controller */
+static u32 amd64_get_dct_base(struct amd64_pvt *pvt, int dct, int csrow)
+{
+       if (dct == 0)
+               return pvt->dcsb0[csrow];
+       else
+               return pvt->dcsb1[csrow];
+}
+
+/*
+ * Return the 'mask' address the i'th CS entry. This function is needed because
+ * there number of DCSM registers on Rev E and prior vs Rev F and later is
+ * different.
+ */
+static u32 amd64_get_dct_mask(struct amd64_pvt *pvt, int dct, int csrow)
+{
+       if (dct == 0)
+               return pvt->dcsm0[amd64_map_to_dcs_mask(pvt, csrow)];
+       else
+               return pvt->dcsm1[amd64_map_to_dcs_mask(pvt, csrow)];
+}
+
+
+/*
+ * In *base and *limit, pass back the full 40-bit base and limit physical
+ * addresses for the node given by node_id.  This information is obtained from
+ * DRAM Base (section 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers. The
+ * base and limit addresses are of type SysAddr, as defined at the start of
+ * section 3.4.4 (p. 70).  They are the lowest and highest physical addresses
+ * in the address range they represent.
+ */
+static void amd64_get_base_and_limit(struct amd64_pvt *pvt, int node_id,
+                              u64 *base, u64 *limit)
+{
+       *base = pvt->dram_base[node_id];
+       *limit = pvt->dram_limit[node_id];
+}
+
+/*
+ * Return 1 if the SysAddr given by sys_addr matches the base/limit associated
+ * with node_id
+ */
+static int amd64_base_limit_match(struct amd64_pvt *pvt,
+                                       u64 sys_addr, int node_id)
+{
+       u64 base, limit, addr;
+
+       amd64_get_base_and_limit(pvt, node_id, &base, &limit);
+
+       /* The K8 treats this as a 40-bit value.  However, bits 63-40 will be
+        * all ones if the most significant implemented address bit is 1.
+        * Here we discard bits 63-40.  See section 3.4.2 of AMD publication
+        * 24592: AMD x86-64 Architecture Programmer's Manual Volume 1
+        * Application Programming.
+        */
+       addr = sys_addr & 0x000000ffffffffffull;
+
+       return (addr >= base) && (addr <= limit);
+}
+
+/*
+ * Attempt to map a SysAddr to a node. On success, return a pointer to the
+ * mem_ctl_info structure for the node that the SysAddr maps to.
+ *
+ * On failure, return NULL.
+ */
+static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
+                                               u64 sys_addr)
+{
+       struct amd64_pvt *pvt;
+       int node_id;
+       u32 intlv_en, bits;
+
+       /*
+        * Here we use the DRAM Base (section 3.4.4.1) and DRAM Limit (section
+        * 3.4.4.2) registers to map the SysAddr to a node ID.
+        */
+       pvt = mci->pvt_info;
+
+       /*
+        * The value of this field should be the same for all DRAM Base
+        * registers.  Therefore we arbitrarily choose to read it from the
+        * register for node 0.
+        */
+       intlv_en = pvt->dram_IntlvEn[0];
+
+       if (intlv_en == 0) {
+               for (node_id = 0; ; ) {
+                       if (amd64_base_limit_match(pvt, sys_addr, node_id))
+                               break;
+
+                       if (++node_id >= DRAM_REG_COUNT)
+                               goto err_no_match;
+               }
+               goto found;
+       }
+
+       if (unlikely((intlv_en != (0x01 << 8)) &&
+                    (intlv_en != (0x03 << 8)) &&
+                    (intlv_en != (0x07 << 8)))) {
+               amd64_printk(KERN_WARNING, "junk value of 0x%x extracted from "
+                            "IntlvEn field of DRAM Base Register for node 0: "
+                            "This probably indicates a BIOS bug.\n", intlv_en);
+               return NULL;
+       }
+
+       bits = (((u32) sys_addr) >> 12) & intlv_en;
+
+       for (node_id = 0; ; ) {
+               if ((pvt->dram_limit[node_id] & intlv_en) == bits)
+                       break;  /* intlv_sel field matches */
+
+               if (++node_id >= DRAM_REG_COUNT)
+                       goto err_no_match;
+       }
+
+       /* sanity test for sys_addr */
+       if (unlikely(!amd64_base_limit_match(pvt, sys_addr, node_id))) {
+               amd64_printk(KERN_WARNING,
+                         "%s(): sys_addr 0x%lx falls outside base/limit "
+                         "address range for node %d with node interleaving "
+                         "enabled.\n", __func__, (unsigned long)sys_addr,
+                         node_id);
+               return NULL;
+       }
+
+found:
+       return edac_mc_find(node_id);
+
+err_no_match:
+       debugf2("sys_addr 0x%lx doesn't match any node\n",
+               (unsigned long)sys_addr);
+
+       return NULL;
+}
+
+/*
+ * Extract the DRAM CS base address from selected csrow register.
+ */
+static u64 base_from_dct_base(struct amd64_pvt *pvt, int csrow)
+{
+       return ((u64) (amd64_get_dct_base(pvt, 0, csrow) & pvt->dcsb_base)) <<
+                               pvt->dcs_shift;
+}
+
+/*
+ * Extract the mask from the dcsb0[csrow] entry in a CPU revision-specific way.
+ */
+static u64 mask_from_dct_mask(struct amd64_pvt *pvt, int csrow)
+{
+       u64 dcsm_bits, other_bits;
+       u64 mask;
+
+       /* Extract bits from DRAM CS Mask. */
+       dcsm_bits = amd64_get_dct_mask(pvt, 0, csrow) & pvt->dcsm_mask;
+
+       other_bits = pvt->dcsm_mask;
+       other_bits = ~(other_bits << pvt->dcs_shift);
+
+       /*
+        * The extracted bits from DCSM belong in the spaces represented by
+        * the cleared bits in other_bits.
+        */
+       mask = (dcsm_bits << pvt->dcs_shift) | other_bits;
+
+       return mask;
+}
+
+/*
+ * @input_addr is an InputAddr associated with the node given by mci. Return the
+ * csrow that input_addr maps to, or -1 on failure (no csrow claims input_addr).
+ */
+static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr)
+{
+       struct amd64_pvt *pvt;
+       int csrow;
+       u64 base, mask;
+
+       pvt = mci->pvt_info;
+
+       /*
+        * Here we use the DRAM CS Base and DRAM CS Mask registers. For each CS
+        * base/mask register pair, test the condition shown near the start of
+        * section 3.5.4 (p. 84, BKDG #26094, K8, revA-E).
+        */
+       for (csrow = 0; csrow < CHIPSELECT_COUNT; csrow++) {
+
+               /* This DRAM chip select is disabled on this node */
+               if ((pvt->dcsb0[csrow] & K8_DCSB_CS_ENABLE) == 0)
+                       continue;
+
+               base = base_from_dct_base(pvt, csrow);
+               mask = ~mask_from_dct_mask(pvt, csrow);
+
+               if ((input_addr & mask) == (base & mask)) {
+                       debugf2("InputAddr 0x%lx matches csrow %d (node %d)\n",
+                               (unsigned long)input_addr, csrow,
+                               pvt->mc_node_id);
+
+                       return csrow;
+               }
+       }
+
+       debugf2("no matching csrow for InputAddr 0x%lx (MC node %d)\n",
+               (unsigned long)input_addr, pvt->mc_node_id);
+
+       return -1;
+}
+
+/*
+ * Return the base value defined by the DRAM Base register for the node
+ * represented by mci.  This function returns the full 40-bit value despite the
+ * fact that the register only stores bits 39-24 of the value. See section
+ * 3.4.4.1 (BKDG #26094, K8, revA-E)
+ */
+static inline u64 get_dram_base(struct mem_ctl_info *mci)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+
+       return pvt->dram_base[pvt->mc_node_id];
+}
+
+/*
+ * Obtain info from the DRAM Hole Address Register (section 3.4.8, pub #26094)
+ * for the node represented by mci. Info is passed back in *hole_base,
+ * *hole_offset, and *hole_size.  Function returns 0 if info is valid or 1 if
+ * info is invalid. Info may be invalid for either of the following reasons:
+ *
+ * - The revision of the node is not E or greater.  In this case, the DRAM Hole
+ *   Address Register does not exist.
+ *
+ * - The DramHoleValid bit is cleared in the DRAM Hole Address Register,
+ *   indicating that its contents are not valid.
+ *
+ * The values passed back in *hole_base, *hole_offset, and *hole_size are
+ * complete 32-bit values despite the fact that the bitfields in the DHAR
+ * only represent bits 31-24 of the base and offset values.
+ */
+int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
+                            u64 *hole_offset, u64 *hole_size)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       u64 base;
+
+       /* only revE and later have the DRAM Hole Address Register */
+       if (boot_cpu_data.x86 == 0xf && pvt->ext_model < OPTERON_CPU_REV_E) {
+               debugf1("  revision %d for node %d does not support DHAR\n",
+                       pvt->ext_model, pvt->mc_node_id);
+               return 1;
+       }
+
+       /* only valid for Fam10h */
+       if (boot_cpu_data.x86 == 0x10 &&
+           (pvt->dhar & F10_DRAM_MEM_HOIST_VALID) == 0) {
+               debugf1("  Dram Memory Hoisting is DISABLED on this system\n");
+               return 1;
+       }
+
+       if ((pvt->dhar & DHAR_VALID) == 0) {
+               debugf1("  Dram Memory Hoisting is DISABLED on this node %d\n",
+                       pvt->mc_node_id);
+               return 1;
+       }
+
+       /* This node has Memory Hoisting */
+
+       /* +------------------+--------------------+--------------------+-----
+        * | memory           | DRAM hole          | relocated          |
+        * | [0, (x - 1)]     | [x, 0xffffffff]    | addresses from     |
+        * |                  |                    | DRAM hole          |
+        * |                  |                    | [0x100000000,      |
+        * |                  |                    |  (0x100000000+     |
+        * |                  |                    |   (0xffffffff-x))] |
+        * +------------------+--------------------+--------------------+-----
+        *
+        * Above is a diagram of physical memory showing the DRAM hole and the
+        * relocated addresses from the DRAM hole.  As shown, the DRAM hole
+        * starts at address x (the base address) and extends through address
+        * 0xffffffff.  The DRAM Hole Address Register (DHAR) relocates the
+        * addresses in the hole so that they start at 0x100000000.
+        */
+
+       base = dhar_base(pvt->dhar);
+
+       *hole_base = base;
+       *hole_size = (0x1ull << 32) - base;
+
+       if (boot_cpu_data.x86 > 0xf)
+               *hole_offset = f10_dhar_offset(pvt->dhar);
+       else
+               *hole_offset = k8_dhar_offset(pvt->dhar);
+
+       debugf1("  DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n",
+               pvt->mc_node_id, (unsigned long)*hole_base,
+               (unsigned long)*hole_offset, (unsigned long)*hole_size);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(amd64_get_dram_hole_info);
+
+/*
+ * Return the DramAddr that the SysAddr given by @sys_addr maps to.  It is
+ * assumed that sys_addr maps to the node given by mci.
+ *
+ * The first part of section 3.4.4 (p. 70) shows how the DRAM Base (section
+ * 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers are used to translate a
+ * SysAddr to a DramAddr. If the DRAM Hole Address Register (DHAR) is enabled,
+ * then it is also involved in translating a SysAddr to a DramAddr. Sections
+ * 3.4.8 and 3.5.8.2 describe the DHAR and how it is used for memory hoisting.
+ * These parts of the documentation are unclear. I interpret them as follows:
+ *
+ * When node n receives a SysAddr, it processes the SysAddr as follows:
+ *
+ * 1. It extracts the DRAMBase and DRAMLimit values from the DRAM Base and DRAM
+ *    Limit registers for node n. If the SysAddr is not within the range
+ *    specified by the base and limit values, then node n ignores the Sysaddr
+ *    (since it does not map to node n). Otherwise continue to step 2 below.
+ *
+ * 2. If the DramHoleValid bit of the DHAR for node n is clear, the DHAR is
+ *    disabled so skip to step 3 below. Otherwise see if the SysAddr is within
+ *    the range of relocated addresses (starting at 0x100000000) from the DRAM
+ *    hole. If not, skip to step 3 below. Else get the value of the
+ *    DramHoleOffset field from the DHAR. To obtain the DramAddr, subtract the
+ *    offset defined by this value from the SysAddr.
+ *
+ * 3. Obtain the base address for node n from the DRAMBase field of the DRAM
+ *    Base register for node n. To obtain the DramAddr, subtract the base
+ *    address from the SysAddr, as shown near the start of section 3.4.4 (p.70).
+ */
+static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)
+{
+       u64 dram_base, hole_base, hole_offset, hole_size, dram_addr;
+       int ret = 0;
+
+       dram_base = get_dram_base(mci);
+
+       ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
+                                     &hole_size);
+       if (!ret) {
+               if ((sys_addr >= (1ull << 32)) &&
+                   (sys_addr < ((1ull << 32) + hole_size))) {
+                       /* use DHAR to translate SysAddr to DramAddr */
+                       dram_addr = sys_addr - hole_offset;
+
+                       debugf2("using DHAR to translate SysAddr 0x%lx to "
+                               "DramAddr 0x%lx\n",
+                               (unsigned long)sys_addr,
+                               (unsigned long)dram_addr);
+
+                       return dram_addr;
+               }
+       }
+
+       /*
+        * Translate the SysAddr to a DramAddr as shown near the start of
+        * section 3.4.4 (p. 70).  Although sys_addr is a 64-bit value, the k8
+        * only deals with 40-bit values.  Therefore we discard bits 63-40 of
+        * sys_addr below.  If bit 39 of sys_addr is 1 then the bits we
+        * discard are all 1s.  Otherwise the bits we discard are all 0s.  See
+        * section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture
+        * Programmer's Manual Volume 1 Application Programming.
+        */
+       dram_addr = (sys_addr & 0xffffffffffull) - dram_base;
+
+       debugf2("using DRAM Base register to translate SysAddr 0x%lx to "
+               "DramAddr 0x%lx\n", (unsigned long)sys_addr,
+               (unsigned long)dram_addr);
+       return dram_addr;
+}
+
+/*
+ * @intlv_en is the value of the IntlvEn field from a DRAM Base register
+ * (section 3.4.4.1).  Return the number of bits from a SysAddr that are used
+ * for node interleaving.
+ */
+static int num_node_interleave_bits(unsigned intlv_en)
+{
+       static const int intlv_shift_table[] = { 0, 1, 0, 2, 0, 0, 0, 3 };
+       int n;
+
+       BUG_ON(intlv_en > 7);
+       n = intlv_shift_table[intlv_en];
+       return n;
+}
+
+/* Translate the DramAddr given by @dram_addr to an InputAddr. */
+static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr)
+{
+       struct amd64_pvt *pvt;
+       int intlv_shift;
+       u64 input_addr;
+
+       pvt = mci->pvt_info;
+
+       /*
+        * See the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E)
+        * concerning translating a DramAddr to an InputAddr.
+        */
+       intlv_shift = num_node_interleave_bits(pvt->dram_IntlvEn[0]);
+       input_addr = ((dram_addr >> intlv_shift) & 0xffffff000ull) +
+           (dram_addr & 0xfff);
+
+       debugf2("  Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n",
+               intlv_shift, (unsigned long)dram_addr,
+               (unsigned long)input_addr);
+
+       return input_addr;
+}
+
+/*
+ * Translate the SysAddr represented by @sys_addr to an InputAddr.  It is
+ * assumed that @sys_addr maps to the node given by mci.
+ */
+static u64 sys_addr_to_input_addr(struct mem_ctl_info *mci, u64 sys_addr)
+{
+       u64 input_addr;
+
+       input_addr =
+           dram_addr_to_input_addr(mci, sys_addr_to_dram_addr(mci, sys_addr));
+
+       debugf2("SysAdddr 0x%lx translates to InputAddr 0x%lx\n",
+               (unsigned long)sys_addr, (unsigned long)input_addr);
+
+       return input_addr;
+}
+
+
+/*
+ * @input_addr is an InputAddr associated with the node represented by mci.
+ * Translate @input_addr to a DramAddr and return the result.
+ */
+static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)
+{
+       struct amd64_pvt *pvt;
+       int node_id, intlv_shift;
+       u64 bits, dram_addr;
+       u32 intlv_sel;
+
+       /*
+        * Near the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E)
+        * shows how to translate a DramAddr to an InputAddr. Here we reverse
+        * this procedure. When translating from a DramAddr to an InputAddr, the
+        * bits used for node interleaving are discarded.  Here we recover these
+        * bits from the IntlvSel field of the DRAM Limit register (section
+        * 3.4.4.2) for the node that input_addr is associated with.
+        */
+       pvt = mci->pvt_info;
+       node_id = pvt->mc_node_id;
+       BUG_ON((node_id < 0) || (node_id > 7));
+
+       intlv_shift = num_node_interleave_bits(pvt->dram_IntlvEn[0]);
+
+       if (intlv_shift == 0) {
+               debugf1("    InputAddr 0x%lx translates to DramAddr of "
+                       "same value\n", (unsigned long)input_addr);
+
+               return input_addr;
+       }
+
+       bits = ((input_addr & 0xffffff000ull) << intlv_shift) +
+           (input_addr & 0xfff);
+
+       intlv_sel = pvt->dram_IntlvSel[node_id] & ((1 << intlv_shift) - 1);
+       dram_addr = bits + (intlv_sel << 12);
+
+       debugf1("InputAddr 0x%lx translates to DramAddr 0x%lx "
+               "(%d node interleave bits)\n", (unsigned long)input_addr,
+               (unsigned long)dram_addr, intlv_shift);
+
+       return dram_addr;
+}
+
+/*
+ * @dram_addr is a DramAddr that maps to the node represented by mci. Convert
+ * @dram_addr to a SysAddr.
+ */
+static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       u64 hole_base, hole_offset, hole_size, base, limit, sys_addr;
+       int ret = 0;
+
+       ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
+                                     &hole_size);
+       if (!ret) {
+               if ((dram_addr >= hole_base) &&
+                   (dram_addr < (hole_base + hole_size))) {
+                       sys_addr = dram_addr + hole_offset;
+
+                       debugf1("using DHAR to translate DramAddr 0x%lx to "
+                               "SysAddr 0x%lx\n", (unsigned long)dram_addr,
+                               (unsigned long)sys_addr);
+
+                       return sys_addr;
+               }
+       }
+
+       amd64_get_base_and_limit(pvt, pvt->mc_node_id, &base, &limit);
+       sys_addr = dram_addr + base;
+
+       /*
+        * The sys_addr we have computed up to this point is a 40-bit value
+        * because the k8 deals with 40-bit values.  However, the value we are
+        * supposed to return is a full 64-bit physical address.  The AMD
+        * x86-64 architecture specifies that the most significant implemented
+        * address bit through bit 63 of a physical address must be either all
+        * 0s or all 1s.  Therefore we sign-extend the 40-bit sys_addr to a
+        * 64-bit value below.  See section 3.4.2 of AMD publication 24592:
+        * AMD x86-64 Architecture Programmer's Manual Volume 1 Application
+        * Programming.
+        */
+       sys_addr |= ~((sys_addr & (1ull << 39)) - 1);
+
+       debugf1("    Node %d, DramAddr 0x%lx to SysAddr 0x%lx\n",
+               pvt->mc_node_id, (unsigned long)dram_addr,
+               (unsigned long)sys_addr);
+
+       return sys_addr;
+}
+
+/*
+ * @input_addr is an InputAddr associated with the node given by mci. Translate
+ * @input_addr to a SysAddr.
+ */
+static inline u64 input_addr_to_sys_addr(struct mem_ctl_info *mci,
+                                        u64 input_addr)
+{
+       return dram_addr_to_sys_addr(mci,
+                                    input_addr_to_dram_addr(mci, input_addr));
+}
+
+/*
+ * Find the minimum and maximum InputAddr values that map to the given @csrow.
+ * Pass back these values in *input_addr_min and *input_addr_max.
+ */
+static void find_csrow_limits(struct mem_ctl_info *mci, int csrow,
+                             u64 *input_addr_min, u64 *input_addr_max)
+{
+       struct amd64_pvt *pvt;
+       u64 base, mask;
+
+       pvt = mci->pvt_info;
+       BUG_ON((csrow < 0) || (csrow >= CHIPSELECT_COUNT));
+
+       base = base_from_dct_base(pvt, csrow);
+       mask = mask_from_dct_mask(pvt, csrow);
+
+       *input_addr_min = base & ~mask;
+       *input_addr_max = base | mask | pvt->dcs_mask_notused;
+}
+
+/*
+ * Extract error address from MCA NB Address Low (section 3.6.4.5) and MCA NB
+ * Address High (section 3.6.4.6) register values and return the result. Address
+ * is located in the info structure (nbeah and nbeal), the encoding is device
+ * specific.
+ */
+static u64 extract_error_address(struct mem_ctl_info *mci,
+                                struct amd64_error_info_regs *info)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+
+       return pvt->ops->get_error_address(mci, info);
+}
+
+
+/* Map the Error address to a PAGE and PAGE OFFSET. */
+static inline void error_address_to_page_and_offset(u64 error_address,
+                                                   u32 *page, u32 *offset)
+{
+       *page = (u32) (error_address >> PAGE_SHIFT);
+       *offset = ((u32) error_address) & ~PAGE_MASK;
+}
+
+/*
+ * @sys_addr is an error address (a SysAddr) extracted from the MCA NB Address
+ * Low (section 3.6.4.5) and MCA NB Address High (section 3.6.4.6) registers
+ * of a node that detected an ECC memory error.  mci represents the node that
+ * the error address maps to (possibly different from the node that detected
+ * the error).  Return the number of the csrow that sys_addr maps to, or -1 on
+ * error.
+ */
+static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)
+{
+       int csrow;
+
+       csrow = input_addr_to_csrow(mci, sys_addr_to_input_addr(mci, sys_addr));
+
+       if (csrow == -1)
+               amd64_mc_printk(mci, KERN_ERR,
+                            "Failed to translate InputAddr to csrow for "
+                            "address 0x%lx\n", (unsigned long)sys_addr);
+       return csrow;
+}
+
+static int get_channel_from_ecc_syndrome(unsigned short syndrome);
+
+static void amd64_cpu_display_info(struct amd64_pvt *pvt)
+{
+       if (boot_cpu_data.x86 == 0x11)
+               edac_printk(KERN_DEBUG, EDAC_MC, "F11h CPU detected\n");
+       else if (boot_cpu_data.x86 == 0x10)
+               edac_printk(KERN_DEBUG, EDAC_MC, "F10h CPU detected\n");
+       else if (boot_cpu_data.x86 == 0xf)
+               edac_printk(KERN_DEBUG, EDAC_MC, "%s detected\n",
+                       (pvt->ext_model >= OPTERON_CPU_REV_F) ?
+                       "Rev F or later" : "Rev E or earlier");
+       else
+               /* we'll hardly ever ever get here */
+               edac_printk(KERN_ERR, EDAC_MC, "Unknown cpu!\n");
+}
+
+/*
+ * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
+ * are ECC capable.
+ */
+static enum edac_type amd64_determine_edac_cap(struct amd64_pvt *pvt)
+{
+       int bit;
+       enum dev_type edac_cap = EDAC_NONE;
+
+       bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= OPTERON_CPU_REV_F)
+               ? 19
+               : 17;
+
+       if (pvt->dclr0 >> BIT(bit))
+               edac_cap = EDAC_FLAG_SECDED;
+
+       return edac_cap;
+}
+
+
+static void f10_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt,
+                                        int ganged);
+
+/* Display and decode various NB registers for debug purposes. */
+static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
+{
+       int ganged;
+
+       debugf1("  nbcap:0x%8.08x DctDualCap=%s DualNode=%s 8-Node=%s\n",
+               pvt->nbcap,
+               (pvt->nbcap & K8_NBCAP_DCT_DUAL) ? "True" : "False",
+               (pvt->nbcap & K8_NBCAP_DUAL_NODE) ? "True" : "False",
+               (pvt->nbcap & K8_NBCAP_8_NODE) ? "True" : "False");
+       debugf1("    ECC Capable=%s   ChipKill Capable=%s\n",
+               (pvt->nbcap & K8_NBCAP_SECDED) ? "True" : "False",
+               (pvt->nbcap & K8_NBCAP_CHIPKILL) ? "True" : "False");
+       debugf1("  DramCfg0-low=0x%08x DIMM-ECC=%s Parity=%s Width=%s\n",
+               pvt->dclr0,
+               (pvt->dclr0 & BIT(19)) ?  "Enabled" : "Disabled",
+               (pvt->dclr0 & BIT(8)) ?  "Enabled" : "Disabled",
+               (pvt->dclr0 & BIT(11)) ?  "128b" : "64b");
+       debugf1("    DIMM x4 Present: L0=%s L1=%s L2=%s L3=%s  DIMM Type=%s\n",
+               (pvt->dclr0 & BIT(12)) ?  "Y" : "N",
+               (pvt->dclr0 & BIT(13)) ?  "Y" : "N",
+               (pvt->dclr0 & BIT(14)) ?  "Y" : "N",
+               (pvt->dclr0 & BIT(15)) ?  "Y" : "N",
+               (pvt->dclr0 & BIT(16)) ?  "UN-Buffered" : "Buffered");
+
+
+       debugf1("  online-spare: 0x%8.08x\n", pvt->online_spare);
+
+       if (boot_cpu_data.x86 == 0xf) {
+               debugf1("  dhar: 0x%8.08x Base=0x%08x Offset=0x%08x\n",
+                       pvt->dhar, dhar_base(pvt->dhar),
+                       k8_dhar_offset(pvt->dhar));
+               debugf1("      DramHoleValid=%s\n",
+                       (pvt->dhar & DHAR_VALID) ?  "True" : "False");
+
+               debugf1("  dbam-dkt: 0x%8.08x\n", pvt->dbam0);
+
+               /* everything below this point is Fam10h and above */
+               return;
+
+       } else {
+               debugf1("  dhar: 0x%8.08x Base=0x%08x Offset=0x%08x\n",
+                       pvt->dhar, dhar_base(pvt->dhar),
+                       f10_dhar_offset(pvt->dhar));
+               debugf1("    DramMemHoistValid=%s DramHoleValid=%s\n",
+                       (pvt->dhar & F10_DRAM_MEM_HOIST_VALID) ?
+                       "True" : "False",
+                       (pvt->dhar & DHAR_VALID) ?
+                       "True" : "False");
+       }
+
+       /* Only if NOT ganged does dcl1 have valid info */
+       if (!dct_ganging_enabled(pvt)) {
+               debugf1("  DramCfg1-low=0x%08x DIMM-ECC=%s Parity=%s "
+                       "Width=%s\n", pvt->dclr1,
+                       (pvt->dclr1 & BIT(19)) ?  "Enabled" : "Disabled",
+                       (pvt->dclr1 & BIT(8)) ?  "Enabled" : "Disabled",
+                       (pvt->dclr1 & BIT(11)) ?  "128b" : "64b");
+               debugf1("    DIMM x4 Present: L0=%s L1=%s L2=%s L3=%s  "
+                       "DIMM Type=%s\n",
+                       (pvt->dclr1 & BIT(12)) ?  "Y" : "N",
+                       (pvt->dclr1 & BIT(13)) ?  "Y" : "N",
+                       (pvt->dclr1 & BIT(14)) ?  "Y" : "N",
+                       (pvt->dclr1 & BIT(15)) ?  "Y" : "N",
+                       (pvt->dclr1 & BIT(16)) ?  "UN-Buffered" : "Buffered");
+       }
+
+       /*
+        * Determine if ganged and then dump memory sizes for first controller,
+        * and if NOT ganged dump info for 2nd controller.
+        */
+       ganged = dct_ganging_enabled(pvt);
+
+       f10_debug_display_dimm_sizes(0, pvt, ganged);
+
+       if (!ganged)
+               f10_debug_display_dimm_sizes(1, pvt, ganged);
+}
+
+/* Read in both of DBAM registers */
+static void amd64_read_dbam_reg(struct amd64_pvt *pvt)
+{
+       int err = 0;
+       unsigned int reg;
+
+       reg = DBAM0;
+       err = pci_read_config_dword(pvt->dram_f2_ctl, reg, &pvt->dbam0);
+       if (err)
+               goto err_reg;
+
+       if (boot_cpu_data.x86 >= 0x10) {
+               reg = DBAM1;
+               err = pci_read_config_dword(pvt->dram_f2_ctl, reg, &pvt->dbam1);
+
+               if (err)
+                       goto err_reg;
+       }
+
+err_reg:
+       debugf0("Error reading F2x%03x.\n", reg);
+}
+
+/*
+ * NOTE: CPU Revision Dependent code: Rev E and Rev F
+ *
+ * Set the DCSB and DCSM mask values depending on the CPU revision value. Also
+ * set the shift factor for the DCSB and DCSM values.
+ *
+ * ->dcs_mask_notused, RevE:
+ *
+ * To find the max InputAddr for the csrow, start with the base address and set
+ * all bits that are "don't care" bits in the test at the start of section
+ * 3.5.4 (p. 84).
+ *
+ * The "don't care" bits are all set bits in the mask and all bits in the gaps
+ * between bit ranges [35:25] and [19:13]. The value REV_E_DCS_NOTUSED_BITS
+ * represents bits [24:20] and [12:0], which are all bits in the above-mentioned
+ * gaps.
+ *
+ * ->dcs_mask_notused, RevF and later:
+ *
+ * To find the max InputAddr for the csrow, start with the base address and set
+ * all bits that are "don't care" bits in the test at the start of NPT section
+ * 4.5.4 (p. 87).
+ *
+ * The "don't care" bits are all set bits in the mask and all bits in the gaps
+ * between bit ranges [36:27] and [21:13].
+ *
+ * The value REV_F_F1Xh_DCS_NOTUSED_BITS represents bits [26:22] and [12:0],
+ * which are all bits in the above-mentioned gaps.
+ */
+static void amd64_set_dct_base_and_mask(struct amd64_pvt *pvt)
+{
+       if (pvt->ext_model >= OPTERON_CPU_REV_F) {
+               pvt->dcsb_base          = REV_F_F1Xh_DCSB_BASE_BITS;
+               pvt->dcsm_mask          = REV_F_F1Xh_DCSM_MASK_BITS;
+               pvt->dcs_mask_notused   = REV_F_F1Xh_DCS_NOTUSED_BITS;
+               pvt->dcs_shift          = REV_F_F1Xh_DCS_SHIFT;
+
+               switch (boot_cpu_data.x86) {
+               case 0xf:
+                       pvt->num_dcsm = REV_F_DCSM_COUNT;
+                       break;
+
+               case 0x10:
+                       pvt->num_dcsm = F10_DCSM_COUNT;
+                       break;
+
+               case 0x11:
+                       pvt->num_dcsm = F11_DCSM_COUNT;
+                       break;
+
+               default:
+                       amd64_printk(KERN_ERR, "Unsupported family!\n");
+                       break;
+               }
+       } else {
+               pvt->dcsb_base          = REV_E_DCSB_BASE_BITS;
+               pvt->dcsm_mask          = REV_E_DCSM_MASK_BITS;
+               pvt->dcs_mask_notused   = REV_E_DCS_NOTUSED_BITS;
+               pvt->dcs_shift          = REV_E_DCS_SHIFT;
+               pvt->num_dcsm           = REV_E_DCSM_COUNT;
+       }
+}
+
+/*
+ * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask hw registers
+ */
+static void amd64_read_dct_base_mask(struct amd64_pvt *pvt)
+{
+       int cs, reg, err = 0;
+
+       amd64_set_dct_base_and_mask(pvt);
+
+       for (cs = 0; cs < CHIPSELECT_COUNT; cs++) {
+               reg = K8_DCSB0 + (cs * 4);
+               err = pci_read_config_dword(pvt->dram_f2_ctl, reg,
+                                               &pvt->dcsb0[cs]);
+               if (unlikely(err))
+                       debugf0("Reading K8_DCSB0[%d] failed\n", cs);
+               else
+                       debugf0("  DCSB0[%d]=0x%08x reg: F2x%x\n",
+                               cs, pvt->dcsb0[cs], reg);
+
+               /* If DCT are NOT ganged, then read in DCT1's base */
+               if (boot_cpu_data.x86 >= 0x10 && !dct_ganging_enabled(pvt)) {
+                       reg = F10_DCSB1 + (cs * 4);
+                       err = pci_read_config_dword(pvt->dram_f2_ctl, reg,
+                                                       &pvt->dcsb1[cs]);
+                       if (unlikely(err))
+                               debugf0("Reading F10_DCSB1[%d] failed\n", cs);
+                       else
+                               debugf0("  DCSB1[%d]=0x%08x reg: F2x%x\n",
+                                       cs, pvt->dcsb1[cs], reg);
+               } else {
+                       pvt->dcsb1[cs] = 0;
+               }
+       }
+
+       for (cs = 0; cs < pvt->num_dcsm; cs++) {
+               reg = K8_DCSB0 + (cs * 4);
+               err = pci_read_config_dword(pvt->dram_f2_ctl, reg,
+                                       &pvt->dcsm0[cs]);
+               if (unlikely(err))
+                       debugf0("Reading K8_DCSM0 failed\n");
+               else
+                       debugf0("    DCSM0[%d]=0x%08x reg: F2x%x\n",
+                               cs, pvt->dcsm0[cs], reg);
+
+               /* If DCT are NOT ganged, then read in DCT1's mask */
+               if (boot_cpu_data.x86 >= 0x10 && !dct_ganging_enabled(pvt)) {
+                       reg = F10_DCSM1 + (cs * 4);
+                       err = pci_read_config_dword(pvt->dram_f2_ctl, reg,
+                                       &pvt->dcsm1[cs]);
+                       if (unlikely(err))
+                               debugf0("Reading F10_DCSM1[%d] failed\n", cs);
+                       else
+                               debugf0("    DCSM1[%d]=0x%08x reg: F2x%x\n",
+                                       cs, pvt->dcsm1[cs], reg);
+               } else
+                       pvt->dcsm1[cs] = 0;
+       }
+}
+
+static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt)
+{
+       enum mem_type type;
+
+       if (boot_cpu_data.x86 >= 0x10 || pvt->ext_model >= OPTERON_CPU_REV_F) {
+               /* Rev F and later */
+               type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2;
+       } else {
+               /* Rev E and earlier */
+               type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR;
+       }
+
+       debugf1("  Memory type is: %s\n",
+               (type == MEM_DDR2) ? "MEM_DDR2" :
+               (type == MEM_RDDR2) ? "MEM_RDDR2" :
+               (type == MEM_DDR) ? "MEM_DDR" : "MEM_RDDR");
+
+       return type;
+}
+
+/*
+ * Read the DRAM Configuration Low register. It differs between CG, D & E revs
+ * and the later RevF memory controllers (DDR vs DDR2)
+ *
+ * Return:
+ *      number of memory channels in operation
+ * Pass back:
+ *      contents of the DCL0_LOW register
+ */
+static int k8_early_channel_count(struct amd64_pvt *pvt)
+{
+       int flag, err = 0;
+
+       err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCLR_0, &pvt->dclr0);
+       if (err)
+               return err;
+
+       if ((boot_cpu_data.x86_model >> 4) >= OPTERON_CPU_REV_F) {
+               /* RevF (NPT) and later */
+               flag = pvt->dclr0 & F10_WIDTH_128;
+       } else {
+               /* RevE and earlier */
+               flag = pvt->dclr0 & REVE_WIDTH_128;
+       }
+
+       /* not used */
+       pvt->dclr1 = 0;
+
+       return (flag) ? 2 : 1;
+}
+
+/* extract the ERROR ADDRESS for the K8 CPUs */
+static u64 k8_get_error_address(struct mem_ctl_info *mci,
+                               struct amd64_error_info_regs *info)
+{
+       return (((u64) (info->nbeah & 0xff)) << 32) +
+                       (info->nbeal & ~0x03);
+}
+
+/*
+ * Read the Base and Limit registers for K8 based Memory controllers; extract
+ * fields from the 'raw' reg into separate data fields
+ *
+ * Isolates: BASE, LIMIT, IntlvEn, IntlvSel, RW_EN
+ */
+static void k8_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
+{
+       u32 low;
+       u32 off = dram << 3;    /* 8 bytes between DRAM entries */
+       int err;
+
+       err = pci_read_config_dword(pvt->addr_f1_ctl,
+                                   K8_DRAM_BASE_LOW + off, &low);
+       if (err)
+               debugf0("Reading K8_DRAM_BASE_LOW failed\n");
+
+       /* Extract parts into separate data entries */
+       pvt->dram_base[dram] = ((u64) low & 0xFFFF0000) << 8;
+       pvt->dram_IntlvEn[dram] = (low >> 8) & 0x7;
+       pvt->dram_rw_en[dram] = (low & 0x3);
+
+       err = pci_read_config_dword(pvt->addr_f1_ctl,
+                                   K8_DRAM_LIMIT_LOW + off, &low);
+       if (err)
+               debugf0("Reading K8_DRAM_LIMIT_LOW failed\n");
+
+       /*
+        * Extract parts into separate data entries. Limit is the HIGHEST memory
+        * location of the region, so lower 24 bits need to be all ones
+        */
+       pvt->dram_limit[dram] = (((u64) low & 0xFFFF0000) << 8) | 0x00FFFFFF;
+       pvt->dram_IntlvSel[dram] = (low >> 8) & 0x7;
+       pvt->dram_DstNode[dram] = (low & 0x7);
+}
+
+static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
+                                       struct amd64_error_info_regs *info,
+                                       u64 SystemAddress)
+{
+       struct mem_ctl_info *src_mci;
+       unsigned short syndrome;
+       int channel, csrow;
+       u32 page, offset;
+
+       /* Extract the syndrome parts and form a 16-bit syndrome */
+       syndrome = EXTRACT_HIGH_SYNDROME(info->nbsl) << 8;
+       syndrome |= EXTRACT_LOW_SYNDROME(info->nbsh);
+
+       /* CHIPKILL enabled */
+       if (info->nbcfg & K8_NBCFG_CHIPKILL) {
+               channel = get_channel_from_ecc_syndrome(syndrome);
+               if (channel < 0) {
+                       /*
+                        * Syndrome didn't map, so we don't know which of the
+                        * 2 DIMMs is in error. So we need to ID 'both' of them
+                        * as suspect.
+                        */
+                       amd64_mc_printk(mci, KERN_WARNING,
+                                      "unknown syndrome 0x%x - possible error "
+                                      "reporting race\n", syndrome);
+                       edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
+                       return;
+               }
+       } else {
+               /*
+                * non-chipkill ecc mode
+                *
+                * The k8 documentation is unclear about how to determine the
+                * channel number when using non-chipkill memory.  This method
+                * was obtained from email communication with someone at AMD.
+                * (Wish the email was placed in this comment - norsk)
+                */
+               channel = ((SystemAddress & BIT(3)) != 0);
+       }
+
+       /*
+        * Find out which node the error address belongs to. This may be
+        * different from the node that detected the error.
+        */
+       src_mci = find_mc_by_sys_addr(mci, SystemAddress);
+       if (src_mci) {
+               amd64_mc_printk(mci, KERN_ERR,
+                            "failed to map error address 0x%lx to a node\n",
+                            (unsigned long)SystemAddress);
+               edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
+               return;
+       }
+
+       /* Now map the SystemAddress to a CSROW */
+       csrow = sys_addr_to_csrow(src_mci, SystemAddress);
+       if (csrow < 0) {
+               edac_mc_handle_ce_no_info(src_mci, EDAC_MOD_STR);
+       } else {
+               error_address_to_page_and_offset(SystemAddress, &page, &offset);
+
+               edac_mc_handle_ce(src_mci, page, offset, syndrome, csrow,
+                                 channel, EDAC_MOD_STR);
+       }
+}
+
+/*
+ * determrine the number of PAGES in for this DIMM's size based on its DRAM
+ * Address Mapping.
+ *
+ * First step is to calc the number of bits to shift a value of 1 left to
+ * indicate show many pages. Start with the DBAM value as the starting bits,
+ * then proceed to adjust those shift bits, based on CPU rev and the table.
+ * See BKDG on the DBAM
+ */
+static int k8_dbam_map_to_pages(struct amd64_pvt *pvt, int dram_map)
+{
+       int nr_pages;
+
+       if (pvt->ext_model >= OPTERON_CPU_REV_F) {
+               nr_pages = 1 << (revf_quad_ddr2_shift[dram_map] - PAGE_SHIFT);
+       } else {
+               /*
+                * RevE and less section; this line is tricky. It collapses the
+                * table used by RevD and later to one that matches revisions CG
+                * and earlier.
+                */
+               dram_map -= (pvt->ext_model >= OPTERON_CPU_REV_D) ?
+                               (dram_map > 8 ? 4 : (dram_map > 5 ?
+                               3 : (dram_map > 2 ? 1 : 0))) : 0;
+
+               /* 25 shift is 32MiB minimum DIMM size in RevE and prior */
+               nr_pages = 1 << (dram_map + 25 - PAGE_SHIFT);
+       }
+
+       return nr_pages;
+}
+
+/*
+ * Get the number of DCT channels in use.
+ *
+ * Return:
+ *     number of Memory Channels in operation
+ * Pass back:
+ *     contents of the DCL0_LOW register
+ */
+static int f10_early_channel_count(struct amd64_pvt *pvt)
+{
+       int err = 0, channels = 0;
+       u32 dbam;
+
+       err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCLR_0, &pvt->dclr0);
+       if (err)
+               goto err_reg;
+
+       err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCLR_1, &pvt->dclr1);
+       if (err)
+               goto err_reg;
+
+       /* If we are in 128 bit mode, then we are using 2 channels */
+       if (pvt->dclr0 & F10_WIDTH_128) {
+               debugf0("Data WIDTH is 128 bits - 2 channels\n");
+               channels = 2;
+               return channels;
+       }
+
+       /*
+        * Need to check if in UN-ganged mode: In such, there are 2 channels,
+        * but they are NOT in 128 bit mode and thus the above 'dcl0' status bit
+        * will be OFF.
+        *
+        * Need to check DCT0[0] and DCT1[0] to see if only one of them has
+        * their CSEnable bit on. If so, then SINGLE DIMM case.
+        */
+       debugf0("Data WIDTH is NOT 128 bits - need more decoding\n");
+
+       /*
+        * Check DRAM Bank Address Mapping values for each DIMM to see if there
+        * is more than just one DIMM present in unganged mode. Need to check
+        * both controllers since DIMMs can be placed in either one.
+        */
+       channels = 0;
+       err = pci_read_config_dword(pvt->dram_f2_ctl, DBAM0, &dbam);
+       if (err)
+               goto err_reg;
+
+       if (DBAM_DIMM(0, dbam) > 0)
+               channels++;
+       if (DBAM_DIMM(1, dbam) > 0)
+               channels++;
+       if (DBAM_DIMM(2, dbam) > 0)
+               channels++;
+       if (DBAM_DIMM(3, dbam) > 0)
+               channels++;
+
+       /* If more than 2 DIMMs are present, then we have 2 channels */
+       if (channels > 2)
+               channels = 2;
+       else if (channels == 0) {
+               /* No DIMMs on DCT0, so look at DCT1 */
+               err = pci_read_config_dword(pvt->dram_f2_ctl, DBAM1, &dbam);
+               if (err)
+                       goto err_reg;
+
+               if (DBAM_DIMM(0, dbam) > 0)
+                       channels++;
+               if (DBAM_DIMM(1, dbam) > 0)
+                       channels++;
+               if (DBAM_DIMM(2, dbam) > 0)
+                       channels++;
+               if (DBAM_DIMM(3, dbam) > 0)
+                       channels++;
+
+               if (channels > 2)
+                       channels = 2;
+       }
+
+       /* If we found ALL 0 values, then assume just ONE DIMM-ONE Channel */
+       if (channels == 0)
+               channels = 1;
+
+       debugf0("DIMM count= %d\n", channels);
+
+       return channels;
+
+err_reg:
+       return -1;
+
+}
+
+static int f10_dbam_map_to_pages(struct amd64_pvt *pvt, int dram_map)
+{
+       return 1 << (revf_quad_ddr2_shift[dram_map] - PAGE_SHIFT);
+}
+
+/* Enable extended configuration access via 0xCF8 feature */
+static void amd64_setup(struct amd64_pvt *pvt)
+{
+       u32 reg;
+
+       pci_read_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, &reg);
+
+       pvt->flags.cf8_extcfg = !!(reg & F10_NB_CFG_LOW_ENABLE_EXT_CFG);
+       reg |= F10_NB_CFG_LOW_ENABLE_EXT_CFG;
+       pci_write_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, reg);
+}
+
+/* Restore the extended configuration access via 0xCF8 feature */
+static void amd64_teardown(struct amd64_pvt *pvt)
+{
+       u32 reg;
+
+       pci_read_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, &reg);
+
+       reg &= ~F10_NB_CFG_LOW_ENABLE_EXT_CFG;
+       if (pvt->flags.cf8_extcfg)
+               reg |= F10_NB_CFG_LOW_ENABLE_EXT_CFG;
+       pci_write_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, reg);
+}
+
+static u64 f10_get_error_address(struct mem_ctl_info *mci,
+                       struct amd64_error_info_regs *info)
+{
+       return (((u64) (info->nbeah & 0xffff)) << 32) +
+                       (info->nbeal & ~0x01);
+}
+
+/*
+ * Read the Base and Limit registers for F10 based Memory controllers. Extract
+ * fields from the 'raw' reg into separate data fields.
+ *
+ * Isolates: BASE, LIMIT, IntlvEn, IntlvSel, RW_EN.
+ */
+static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
+{
+       u32 high_offset, low_offset, high_base, low_base, high_limit, low_limit;
+
+       low_offset = K8_DRAM_BASE_LOW + (dram << 3);
+       high_offset = F10_DRAM_BASE_HIGH + (dram << 3);
+
+       /* read the 'raw' DRAM BASE Address register */
+       pci_read_config_dword(pvt->addr_f1_ctl, low_offset, &low_base);
+
+       /* Read from the ECS data register */
+       pci_read_config_dword(pvt->addr_f1_ctl, high_offset, &high_base);
+
+       /* Extract parts into separate data entries */
+       pvt->dram_rw_en[dram] = (low_base & 0x3);
+
+       if (pvt->dram_rw_en[dram] == 0)
+               return;
+
+       pvt->dram_IntlvEn[dram] = (low_base >> 8) & 0x7;
+
+       pvt->dram_base[dram] = (((((u64) high_base & 0x000000FF) << 32) |
+                               ((u64) low_base & 0xFFFF0000))) << 8;
+
+       low_offset = K8_DRAM_LIMIT_LOW + (dram << 3);
+       high_offset = F10_DRAM_LIMIT_HIGH + (dram << 3);
+
+       /* read the 'raw' LIMIT registers */
+       pci_read_config_dword(pvt->addr_f1_ctl, low_offset, &low_limit);
+
+       /* Read from the ECS data register for the HIGH portion */
+       pci_read_config_dword(pvt->addr_f1_ctl, high_offset, &high_limit);
+
+       debugf0("  HW Regs: BASE=0x%08x-%08x      LIMIT=  0x%08x-%08x\n",
+               high_base, low_base, high_limit, low_limit);
+
+       pvt->dram_DstNode[dram] = (low_limit & 0x7);
+       pvt->dram_IntlvSel[dram] = (low_limit >> 8) & 0x7;
+
+       /*
+        * Extract address values and form a LIMIT address. Limit is the HIGHEST
+        * memory location of the region, so low 24 bits need to be all ones.
+        */
+       low_limit |= 0x0000FFFF;
+       pvt->dram_limit[dram] =
+               ((((u64) high_limit << 32) + (u64) low_limit) << 8) | (0xFF);
+}
+
+static void f10_read_dram_ctl_register(struct amd64_pvt *pvt)
+{
+       int err = 0;
+
+       err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCTL_SEL_LOW,
+                                   &pvt->dram_ctl_select_low);
+       if (err) {
+               debugf0("Reading F10_DCTL_SEL_LOW failed\n");
+       } else {
+               debugf0("DRAM_DCTL_SEL_LOW=0x%x  DctSelBaseAddr=0x%x\n",
+                       pvt->dram_ctl_select_low, dct_sel_baseaddr(pvt));
+
+               debugf0("  DRAM DCTs are=%s DRAM Is=%s DRAM-Ctl-"
+                               "sel-hi-range=%s\n",
+                       (dct_ganging_enabled(pvt) ? "GANGED" : "NOT GANGED"),
+                       (dct_dram_enabled(pvt) ? "Enabled"   : "Disabled"),
+                       (dct_high_range_enabled(pvt) ? "Enabled" : "Disabled"));
+
+               debugf0("  DctDatIntLv=%s MemCleared=%s DctSelIntLvAddr=0x%x\n",
+                       (dct_data_intlv_enabled(pvt) ? "Enabled" : "Disabled"),
+                       (dct_memory_cleared(pvt) ? "True " : "False "),
+                       dct_sel_interleave_addr(pvt));
+       }
+
+       err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCTL_SEL_HIGH,
+                                   &pvt->dram_ctl_select_high);
+       if (err)
+               debugf0("Reading F10_DCTL_SEL_HIGH failed\n");
+}
+
+/*
+ * determine channel based on the interleaving mode: F10h BKDG, 2.8.9 Memory
+ * Interleaving Modes.
+ */
+static u32 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
+                               int hi_range_sel, u32 intlv_en)
+{
+       u32 cs, temp, dct_sel_high = (pvt->dram_ctl_select_low >> 1) & 1;
+
+       if (dct_ganging_enabled(pvt))
+               cs = 0;
+       else if (hi_range_sel)
+               cs = dct_sel_high;
+       else if (dct_interleave_enabled(pvt)) {
+               /*
+                * see F2x110[DctSelIntLvAddr] - channel interleave mode
+                */
+               if (dct_sel_interleave_addr(pvt) == 0)
+                       cs = sys_addr >> 6 & 1;
+               else if ((dct_sel_interleave_addr(pvt) >> 1) & 1) {
+                       temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) % 2;
+
+                       if (dct_sel_interleave_addr(pvt) & 1)
+                               cs = (sys_addr >> 9 & 1) ^ temp;
+                       else
+                               cs = (sys_addr >> 6 & 1) ^ temp;
+               } else if (intlv_en & 4)
+                       cs = sys_addr >> 15 & 1;
+               else if (intlv_en & 2)
+                       cs = sys_addr >> 14 & 1;
+               else if (intlv_en & 1)
+                       cs = sys_addr >> 13 & 1;
+               else
+                       cs = sys_addr >> 12 & 1;
+       } else if (dct_high_range_enabled(pvt) && !dct_ganging_enabled(pvt))
+               cs = ~dct_sel_high & 1;
+       else
+               cs = 0;
+
+       return cs;
+}
+
+static inline u32 f10_map_intlv_en_to_shift(u32 intlv_en)
+{
+       if (intlv_en == 1)
+               return 1;
+       else if (intlv_en == 3)
+               return 2;
+       else if (intlv_en == 7)
+               return 3;
+
+       return 0;
+}
+
+/* See F10h BKDG, 2.8.10.2 DctSelBaseOffset Programming */
+static inline u64 f10_get_base_addr_offset(u64 sys_addr, int hi_range_sel,
+                                                u32 dct_sel_base_addr,
+                                                u64 dct_sel_base_off,
+                                                u32 hole_valid, u32 hole_off,
+                                                u64 dram_base)
+{
+       u64 chan_off;
+
+       if (hi_range_sel) {
+               if (!(dct_sel_base_addr & 0xFFFFF800) &&
+                  hole_valid && (sys_addr >= 0x100000000ULL))
+                       chan_off = hole_off << 16;
+               else
+                       chan_off = dct_sel_base_off;
+       } else {
+               if (hole_valid && (sys_addr >= 0x100000000ULL))
+                       chan_off = hole_off << 16;
+               else
+                       chan_off = dram_base & 0xFFFFF8000000ULL;
+       }
+
+       return (sys_addr & 0x0000FFFFFFFFFFC0ULL) -
+                       (chan_off & 0x0000FFFFFF800000ULL);
+}
+
+/* Hack for the time being - Can we get this from BIOS?? */
+#define        CH0SPARE_RANK   0
+#define        CH1SPARE_RANK   1
+
+/*
+ * checks if the csrow passed in is marked as SPARED, if so returns the new
+ * spare row
+ */
+static inline int f10_process_possible_spare(int csrow,
+                               u32 cs, struct amd64_pvt *pvt)
+{
+       u32 swap_done;
+       u32 bad_dram_cs;
+
+       /* Depending on channel, isolate respective SPARING info */
+       if (cs) {
+               swap_done = F10_ONLINE_SPARE_SWAPDONE1(pvt->online_spare);
+               bad_dram_cs = F10_ONLINE_SPARE_BADDRAM_CS1(pvt->online_spare);
+               if (swap_done && (csrow == bad_dram_cs))
+                       csrow = CH1SPARE_RANK;
+       } else {
+               swap_done = F10_ONLINE_SPARE_SWAPDONE0(pvt->online_spare);
+               bad_dram_cs = F10_ONLINE_SPARE_BADDRAM_CS0(pvt->online_spare);
+               if (swap_done && (csrow == bad_dram_cs))
+                       csrow = CH0SPARE_RANK;
+       }
+       return csrow;
+}
+
+/*
+ * Iterate over the DRAM DCT "base" and "mask" registers looking for a
+ * SystemAddr match on the specified 'ChannelSelect' and 'NodeID'
+ *
+ * Return:
+ *     -EINVAL:  NOT FOUND
+ *     0..csrow = Chip-Select Row
+ */
+static int f10_lookup_addr_in_dct(u32 in_addr, u32 nid, u32 cs)
+{
+       struct mem_ctl_info *mci;
+       struct amd64_pvt *pvt;
+       u32 cs_base, cs_mask;
+       int cs_found = -EINVAL;
+       int csrow;
+
+       mci = mci_lookup[nid];
+       if (!mci)
+               return cs_found;
+
+       pvt = mci->pvt_info;
+
+       debugf1("InputAddr=0x%x  channelselect=%d\n", in_addr, cs);
+
+       for (csrow = 0; csrow < CHIPSELECT_COUNT; csrow++) {
+
+               cs_base = amd64_get_dct_base(pvt, cs, csrow);
+               if (!(cs_base & K8_DCSB_CS_ENABLE))
+                       continue;
+
+               /*
+                * We have an ENABLED CSROW, Isolate just the MASK bits of the
+                * target: [28:19] and [13:5], which map to [36:27] and [21:13]
+                * of the actual address.
+                */
+               cs_base &= REV_F_F1Xh_DCSB_BASE_BITS;
+
+               /*
+                * Get the DCT Mask, and ENABLE the reserved bits: [18:16] and
+                * [4:0] to become ON. Then mask off bits [28:0] ([36:8])
+                */
+               cs_mask = amd64_get_dct_mask(pvt, cs, csrow);
+
+               debugf1("    CSROW=%d CSBase=0x%x RAW CSMask=0x%x\n",
+                               csrow, cs_base, cs_mask);
+
+               cs_mask = (cs_mask | 0x0007C01F) & 0x1FFFFFFF;
+
+               debugf1("              Final CSMask=0x%x\n", cs_mask);
+               debugf1("    (InputAddr & ~CSMask)=0x%x "
+                               "(CSBase & ~CSMask)=0x%x\n",
+                               (in_addr & ~cs_mask), (cs_base & ~cs_mask));
+
+               if ((in_addr & ~cs_mask) == (cs_base & ~cs_mask)) {
+                       cs_found = f10_process_possible_spare(csrow, cs, pvt);
+
+                       debugf1(" MATCH csrow=%d\n", cs_found);
+                       break;
+               }
+       }
+       return cs_found;
+}
+
+/* For a given @dram_range, check if @sys_addr falls within it. */
+static int f10_match_to_this_node(struct amd64_pvt *pvt, int dram_range,
+                                 u64 sys_addr, int *nid, int *chan_sel)
+{
+       int node_id, cs_found = -EINVAL, high_range = 0;
+       u32 intlv_en, intlv_sel, intlv_shift, hole_off;
+       u32 hole_valid, tmp, dct_sel_base, channel;
+       u64 dram_base, chan_addr, dct_sel_base_off;
+
+       dram_base = pvt->dram_base[dram_range];
+       intlv_en = pvt->dram_IntlvEn[dram_range];
+
+       node_id = pvt->dram_DstNode[dram_range];
+       intlv_sel = pvt->dram_IntlvSel[dram_range];
+
+       debugf1("(dram=%d) Base=0x%llx SystemAddr= 0x%llx Limit=0x%llx\n",
+               dram_range, dram_base, sys_addr, pvt->dram_limit[dram_range]);
+
+       /*
+        * This assumes that one node's DHAR is the same as all the other
+        * nodes' DHAR.
+        */
+       hole_off = (pvt->dhar & 0x0000FF80);
+       hole_valid = (pvt->dhar & 0x1);
+       dct_sel_base_off = (pvt->dram_ctl_select_high & 0xFFFFFC00) << 16;
+
+       debugf1("   HoleOffset=0x%x  HoleValid=0x%x IntlvSel=0x%x\n",
+                       hole_off, hole_valid, intlv_sel);
+
+       if (intlv_en ||
+           (intlv_sel != ((sys_addr >> 12) & intlv_en)))
+               return -EINVAL;
+
+       dct_sel_base = dct_sel_baseaddr(pvt);
+
+       /*
+        * check whether addresses >= DctSelBaseAddr[47:27] are to be used to
+        * select between DCT0 and DCT1.
+        */
+       if (dct_high_range_enabled(pvt) &&
+          !dct_ganging_enabled(pvt) &&
+          ((sys_addr >> 27) >= (dct_sel_base >> 11)))
+               high_range = 1;
+
+       channel = f10_determine_channel(pvt, sys_addr, high_range, intlv_en);
+
+       chan_addr = f10_get_base_addr_offset(sys_addr, high_range, dct_sel_base,
+                                            dct_sel_base_off, hole_valid,
+                                            hole_off, dram_base);
+
+       intlv_shift = f10_map_intlv_en_to_shift(intlv_en);
+
+       /* remove Node ID (in case of memory interleaving) */
+       tmp = chan_addr & 0xFC0;
+
+       chan_addr = ((chan_addr >> intlv_shift) & 0xFFFFFFFFF000ULL) | tmp;
+
+       /* remove channel interleave and hash */
+       if (dct_interleave_enabled(pvt) &&
+          !dct_high_range_enabled(pvt) &&
+          !dct_ganging_enabled(pvt)) {
+               if (dct_sel_interleave_addr(pvt) != 1)
+                       chan_addr = (chan_addr >> 1) & 0xFFFFFFFFFFFFFFC0ULL;
+               else {
+                       tmp = chan_addr & 0xFC0;
+                       chan_addr = ((chan_addr & 0xFFFFFFFFFFFFC000ULL) >> 1)
+                                       | tmp;
+               }
+       }
+
+       debugf1("   (ChannelAddrLong=0x%llx) >> 8 becomes InputAddr=0x%x\n",
+               chan_addr, (u32)(chan_addr >> 8));
+
+       cs_found = f10_lookup_addr_in_dct(chan_addr >> 8, node_id, channel);
+
+       if (cs_found >= 0) {
+               *nid = node_id;
+               *chan_sel = channel;
+       }
+       return cs_found;
+}
+
+static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
+                                      int *node, int *chan_sel)
+{
+       int dram_range, cs_found = -EINVAL;
+       u64 dram_base, dram_limit;
+
+       for (dram_range = 0; dram_range < DRAM_REG_COUNT; dram_range++) {
+
+               if (!pvt->dram_rw_en[dram_range])
+                       continue;
+
+               dram_base = pvt->dram_base[dram_range];
+               dram_limit = pvt->dram_limit[dram_range];
+
+               if ((dram_base <= sys_addr) && (sys_addr <= dram_limit)) {
+
+                       cs_found = f10_match_to_this_node(pvt, dram_range,
+                                                         sys_addr, node,
+                                                         chan_sel);
+                       if (cs_found >= 0)
+                               break;
+               }
+       }
+       return cs_found;
+}
+
+/*
+ * This the F10h reference code from AMD to map a @sys_addr to NodeID,
+ * CSROW, Channel.
+ *
+ * The @sys_addr is usually an error address received from the hardware.
+ */
+static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
+                                    struct amd64_error_info_regs *info,
+                                    u64 sys_addr)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       u32 page, offset;
+       unsigned short syndrome;
+       int nid, csrow, chan = 0;
+
+       csrow = f10_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);
+
+       if (csrow >= 0) {
+               error_address_to_page_and_offset(sys_addr, &page, &offset);
+
+               syndrome = EXTRACT_HIGH_SYNDROME(info->nbsl) << 8;
+               syndrome |= EXTRACT_LOW_SYNDROME(info->nbsh);
+
+               /*
+                * Is CHIPKILL on? If so, then we can attempt to use the
+                * syndrome to isolate which channel the error was on.
+                */
+               if (pvt->nbcfg & K8_NBCFG_CHIPKILL)
+                       chan = get_channel_from_ecc_syndrome(syndrome);
+
+               if (chan >= 0) {
+                       edac_mc_handle_ce(mci, page, offset, syndrome,
+                                       csrow, chan, EDAC_MOD_STR);
+               } else {
+                       /*
+                        * Channel unknown, report all channels on this
+                        * CSROW as failed.
+                        */
+                       for (chan = 0; chan < mci->csrows[csrow].nr_channels;
+                                                               chan++) {
+                                       edac_mc_handle_ce(mci, page, offset,
+                                                       syndrome,
+                                                       csrow, chan,
+                                                       EDAC_MOD_STR);
+                       }
+               }
+
+       } else {
+               edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
+       }
+}
+
+/*
+ * Input (@index) is the DBAM DIMM value (1 of 4) used as an index into a shift
+ * table (revf_quad_ddr2_shift) which starts at 128MB DIMM size. Index of 0
+ * indicates an empty DIMM slot, as reported by Hardware on empty slots.
+ *
+ * Normalize to 128MB by subracting 27 bit shift.
+ */
+static int map_dbam_to_csrow_size(int index)
+{
+       int mega_bytes = 0;
+
+       if (index > 0 && index <= DBAM_MAX_VALUE)
+               mega_bytes = ((128 << (revf_quad_ddr2_shift[index]-27)));
+
+       return mega_bytes;
+}
+
+/*
+ * debug routine to display the memory sizes of a DIMM (ganged or not) and it
+ * CSROWs as well
+ */
+static void f10_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt,
+                                        int ganged)
+{
+       int dimm, size0, size1;
+       u32 dbam;
+       u32 *dcsb;
+
+       debugf1("  dbam%d: 0x%8.08x  CSROW is %s\n", ctrl,
+                       ctrl ? pvt->dbam1 : pvt->dbam0,
+                       ganged ? "GANGED - dbam1 not used" : "NON-GANGED");
+
+       dbam = ctrl ? pvt->dbam1 : pvt->dbam0;
+       dcsb = ctrl ? pvt->dcsb1 : pvt->dcsb0;
+
+       /* Dump memory sizes for DIMM and its CSROWs */
+       for (dimm = 0; dimm < 4; dimm++) {
+
+               size0 = 0;
+               if (dcsb[dimm*2] & K8_DCSB_CS_ENABLE)
+                       size0 = map_dbam_to_csrow_size(DBAM_DIMM(dimm, dbam));
+
+               size1 = 0;
+               if (dcsb[dimm*2 + 1] & K8_DCSB_CS_ENABLE)
+                       size1 = map_dbam_to_csrow_size(DBAM_DIMM(dimm, dbam));
+
+               debugf1("     CTRL-%d DIMM-%d=%5dMB   CSROW-%d=%5dMB "
+                               "CSROW-%d=%5dMB\n",
+                               ctrl,
+                               dimm,
+                               size0 + size1,
+                               dimm * 2,
+                               size0,
+                               dimm * 2 + 1,
+                               size1);
+       }
+}
+
+/*
+ * Very early hardware probe on pci_probe thread to determine if this module
+ * supports the hardware.
+ *
+ * Return:
+ *      0 for OK
+ *      1 for error
+ */
+static int f10_probe_valid_hardware(struct amd64_pvt *pvt)
+{
+       int ret = 0;
+
+       /*
+        * If we are on a DDR3 machine, we don't know yet if
+        * we support that properly at this time
+        */
+       if ((pvt->dchr0 & F10_DCHR_Ddr3Mode) ||
+           (pvt->dchr1 & F10_DCHR_Ddr3Mode)) {
+
+               amd64_printk(KERN_WARNING,
+                       "%s() This machine is running with DDR3 memory. "
+                       "This is not currently supported. "
+                       "DCHR0=0x%x DCHR1=0x%x\n",
+                       __func__, pvt->dchr0, pvt->dchr1);
+
+               amd64_printk(KERN_WARNING,
+                       "   Contact '%s' module MAINTAINER to help add"
+                       " support.\n",
+                       EDAC_MOD_STR);
+
+               ret = 1;
+
+       }
+       return ret;
+}
+
+/*
+ * There currently are 3 types type of MC devices for AMD Athlon/Opterons
+ * (as per PCI DEVICE_IDs):
+ *
+ * Family K8: That is the Athlon64 and Opteron CPUs. They all have the same PCI
+ * DEVICE ID, even though there is differences between the different Revisions
+ * (CG,D,E,F).
+ *
+ * Family F10h and F11h.
+ *
+ */
+static struct amd64_family_type amd64_family_types[] = {
+       [K8_CPUS] = {
+               .ctl_name = "RevF",
+               .addr_f1_ctl = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
+               .misc_f3_ctl = PCI_DEVICE_ID_AMD_K8_NB_MISC,
+               .ops = {
+                       .early_channel_count = k8_early_channel_count,
+                       .get_error_address = k8_get_error_address,
+                       .read_dram_base_limit = k8_read_dram_base_limit,
+                       .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow,
+                       .dbam_map_to_pages = k8_dbam_map_to_pages,
+               }
+       },
+       [F10_CPUS] = {
+               .ctl_name = "Family 10h",
+               .addr_f1_ctl = PCI_DEVICE_ID_AMD_10H_NB_MAP,
+               .misc_f3_ctl = PCI_DEVICE_ID_AMD_10H_NB_MISC,
+               .ops = {
+                       .probe_valid_hardware = f10_probe_valid_hardware,
+                       .early_channel_count = f10_early_channel_count,
+                       .get_error_address = f10_get_error_address,
+                       .read_dram_base_limit = f10_read_dram_base_limit,
+                       .read_dram_ctl_register = f10_read_dram_ctl_register,
+                       .map_sysaddr_to_csrow = f10_map_sysaddr_to_csrow,
+                       .dbam_map_to_pages = f10_dbam_map_to_pages,
+               }
+       },
+       [F11_CPUS] = {
+               .ctl_name = "Family 11h",
+               .addr_f1_ctl = PCI_DEVICE_ID_AMD_11H_NB_MAP,
+               .misc_f3_ctl = PCI_DEVICE_ID_AMD_11H_NB_MISC,
+               .ops = {
+                       .probe_valid_hardware = f10_probe_valid_hardware,
+                       .early_channel_count = f10_early_channel_count,
+                       .get_error_address = f10_get_error_address,
+                       .read_dram_base_limit = f10_read_dram_base_limit,
+                       .read_dram_ctl_register = f10_read_dram_ctl_register,
+                       .map_sysaddr_to_csrow = f10_map_sysaddr_to_csrow,
+                       .dbam_map_to_pages = f10_dbam_map_to_pages,
+               }
+       },
+};
+
+static struct pci_dev *pci_get_related_function(unsigned int vendor,
+                                               unsigned int device,
+                                               struct pci_dev *related)
+{
+       struct pci_dev *dev = NULL;
+
+       dev = pci_get_device(vendor, device, dev);
+       while (dev) {
+               if ((dev->bus->number == related->bus->number) &&
+                   (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
+                       break;
+               dev = pci_get_device(vendor, device, dev);
+       }
+
+       return dev;
+}
+
+/*
+ * syndrome mapping table for ECC ChipKill devices
+ *
+ * The comment in each row is the token (nibble) number that is in error.
+ * The least significant nibble of the syndrome is the mask for the bits
+ * that are in error (need to be toggled) for the particular nibble.
+ *
+ * Each row contains 16 entries.
+ * The first entry (0th) is the channel number for that row of syndromes.
+ * The remaining 15 entries are the syndromes for the respective Error
+ * bit mask index.
+ *
+ * 1st index entry is 0x0001 mask, indicating that the rightmost bit is the
+ * bit in error.
+ * The 2nd index entry is 0x0010 that the second bit is damaged.
+ * The 3rd index entry is 0x0011 indicating that the rightmost 2 bits
+ * are damaged.
+ * Thus so on until index 15, 0x1111, whose entry has the syndrome
+ * indicating that all 4 bits are damaged.
+ *
+ * A search is performed on this table looking for a given syndrome.
+ *
+ * See the AMD documentation for ECC syndromes. This ECC table is valid
+ * across all the versions of the AMD64 processors.
+ *
+ * A fast lookup is to use the LAST four bits of the 16-bit syndrome as a
+ * COLUMN index, then search all ROWS of that column, looking for a match
+ * with the input syndrome. The ROW value will be the token number.
+ *
+ * The 0'th entry on that row, can be returned as the CHANNEL (0 or 1) of this
+ * error.
+ */
+#define NUMBER_ECC_ROWS  36
+static const unsigned short ecc_chipkill_syndromes[NUMBER_ECC_ROWS][16] = {
+       /* Channel 0 syndromes */
+       {/*0*/  0, 0xe821, 0x7c32, 0x9413, 0xbb44, 0x5365, 0xc776, 0x2f57,
+          0xdd88, 0x35a9, 0xa1ba, 0x499b, 0x66cc, 0x8eed, 0x1afe, 0xf2df },
+       {/*1*/  0, 0x5d31, 0xa612, 0xfb23, 0x9584, 0xc8b5, 0x3396, 0x6ea7,
+          0xeac8, 0xb7f9, 0x4cda, 0x11eb, 0x7f4c, 0x227d, 0xd95e, 0x846f },
+       {/*2*/  0, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+          0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f },
+       {/*3*/  0, 0x2021, 0x3032, 0x1013, 0x4044, 0x6065, 0x7076, 0x5057,
+          0x8088, 0xa0a9, 0xb0ba, 0x909b, 0xc0cc, 0xe0ed, 0xf0fe, 0xd0df },
+       {/*4*/  0, 0x5041, 0xa082, 0xf0c3, 0x9054, 0xc015, 0x30d6, 0x6097,
+          0xe0a8, 0xb0e9, 0x402a, 0x106b, 0x70fc, 0x20bd, 0xd07e, 0x803f },
+       {/*5*/  0, 0xbe21, 0xd732, 0x6913, 0x2144, 0x9f65, 0xf676, 0x4857,
+          0x3288, 0x8ca9, 0xe5ba, 0x5b9b, 0x13cc, 0xaded, 0xc4fe, 0x7adf },
+       {/*6*/  0, 0x4951, 0x8ea2, 0xc7f3, 0x5394, 0x1ac5, 0xdd36, 0x9467,
+          0xa1e8, 0xe8b9, 0x2f4a, 0x661b, 0xf27c, 0xbb2d, 0x7cde, 0x358f },
+       {/*7*/  0, 0x74e1, 0x9872, 0xec93, 0xd6b4, 0xa255, 0x4ec6, 0x3a27,
+          0x6bd8, 0x1f39, 0xf3aa, 0x874b, 0xbd6c, 0xc98d, 0x251e, 0x51ff },
+       {/*8*/  0, 0x15c1, 0x2a42, 0x3f83, 0xcef4, 0xdb35, 0xe4b6, 0xf177,
+          0x4758, 0x5299, 0x6d1a, 0x78db, 0x89ac, 0x9c6d, 0xa3ee, 0xb62f },
+       {/*9*/  0, 0x3d01, 0x1602, 0x2b03, 0x8504, 0xb805, 0x9306, 0xae07,
+          0xca08, 0xf709, 0xdc0a, 0xe10b, 0x4f0c, 0x720d, 0x590e, 0x640f },
+       {/*a*/  0, 0x9801, 0xec02, 0x7403, 0x6b04, 0xf305, 0x8706, 0x1f07,
+          0xbd08, 0x2509, 0x510a, 0xc90b, 0xd60c, 0x4e0d, 0x3a0e, 0xa20f },
+       {/*b*/  0, 0xd131, 0x6212, 0xb323, 0x3884, 0xe9b5, 0x5a96, 0x8ba7,
+          0x1cc8, 0xcdf9, 0x7eda, 0xafeb, 0x244c, 0xf57d, 0x465e, 0x976f },
+       {/*c*/  0, 0xe1d1, 0x7262, 0x93b3, 0xb834, 0x59e5, 0xca56, 0x2b87,
+          0xdc18, 0x3dc9, 0xae7a, 0x4fab, 0x542c, 0x85fd, 0x164e, 0xf79f },
+       {/*d*/  0, 0x6051, 0xb0a2, 0xd0f3, 0x1094, 0x70c5, 0xa036, 0xc067,
+          0x20e8, 0x40b9, 0x904a, 0x601b, 0x307c, 0x502d, 0x80de, 0xe08f },
+       {/*e*/  0, 0xa4c1, 0xf842, 0x5c83, 0xe6f4, 0x4235, 0x1eb6, 0xba77,
+          0x7b58, 0xdf99, 0x831a, 0x27db, 0x9dac, 0x396d, 0x65ee, 0xc12f },
+       {/*f*/  0, 0x11c1, 0x2242, 0x3383, 0xc8f4, 0xd935, 0xeab6, 0xfb77,
+          0x4c58, 0x5d99, 0x6e1a, 0x7fdb, 0x84ac, 0x956d, 0xa6ee, 0xb72f },
+
+       /* Channel 1 syndromes */
+       {/*10*/ 1, 0x45d1, 0x8a62, 0xcfb3, 0x5e34, 0x1be5, 0xd456, 0x9187,
+          0xa718, 0xe2c9, 0x2d7a, 0x68ab, 0xf92c, 0xbcfd, 0x734e, 0x369f },
+       {/*11*/ 1, 0x63e1, 0xb172, 0xd293, 0x14b4, 0x7755, 0xa5c6, 0xc627,
+          0x28d8, 0x4b39, 0x99aa, 0xfa4b, 0x3c6c, 0x5f8d, 0x8d1e, 0xeeff },
+       {/*12*/ 1, 0xb741, 0xd982, 0x6ec3, 0x2254, 0x9515, 0xfbd6, 0x4c97,
+          0x33a8, 0x84e9, 0xea2a, 0x5d6b, 0x11fc, 0xa6bd, 0xc87e, 0x7f3f },
+       {/*13*/ 1, 0xdd41, 0x6682, 0xbbc3, 0x3554, 0xe815, 0x53d6, 0xce97,
+          0x1aa8, 0xc7e9, 0x7c2a, 0xa1fb, 0x2ffc, 0xf2bd, 0x497e, 0x943f },
+       {/*14*/ 1, 0x2bd1, 0x3d62, 0x16b3, 0x4f34, 0x64e5, 0x7256, 0x5987,
+          0x8518, 0xaec9, 0xb87a, 0x93ab, 0xca2c, 0xe1fd, 0xf74e, 0xdc9f },
+       {/*15*/ 1, 0x83c1, 0xc142, 0x4283, 0xa4f4, 0x2735, 0x65b6, 0xe677,
+          0xf858, 0x7b99, 0x391a, 0xbadb, 0x5cac, 0xdf6d, 0x9dee, 0x1e2f },
+       {/*16*/ 1, 0x8fd1, 0xc562, 0x4ab3, 0xa934, 0x26e5, 0x6c56, 0xe387,
+          0xfe18, 0x71c9, 0x3b7a, 0xb4ab, 0x572c, 0xd8fd, 0x924e, 0x1d9f },
+       {/*17*/ 1, 0x4791, 0x89e2, 0xce73, 0x5264, 0x15f5, 0xdb86, 0x9c17,
+          0xa3b8, 0xe429, 0x2a5a, 0x6dcb, 0xf1dc, 0xb64d, 0x783e, 0x3faf },
+       {/*18*/ 1, 0x5781, 0xa9c2, 0xfe43, 0x92a4, 0xc525, 0x3b66, 0x6ce7,
+          0xe3f8, 0xb479, 0x4a3a, 0x1dbb, 0x715c, 0x26dd, 0xd89e, 0x8f1f },
+       {/*19*/ 1, 0xbf41, 0xd582, 0x6ac3, 0x2954, 0x9615, 0xfcd6, 0x4397,
+          0x3ea8, 0x81e9, 0xeb2a, 0x546b, 0x17fc, 0xa8bd, 0xc27e, 0x7d3f },
+       {/*1a*/ 1, 0x9891, 0xe1e2, 0x7273, 0x6464, 0xf7f5, 0x8586, 0x1617,
+          0xb8b8, 0x2b29, 0x595a, 0xcacb, 0xdcdc, 0x4f4d, 0x3d3e, 0xaeaf },
+       {/*1b*/ 1, 0xcce1, 0x4472, 0x8893, 0xfdb4, 0x3f55, 0xb9c6, 0x7527,
+          0x56d8, 0x9a39, 0x12aa, 0xde4b, 0xab6c, 0x678d, 0xef1e, 0x23ff },
+       {/*1c*/ 1, 0xa761, 0xf9b2, 0x5ed3, 0xe214, 0x4575, 0x1ba6, 0xbcc7,
+          0x7328, 0xd449, 0x8a9a, 0x2dfb, 0x913c, 0x365d, 0x688e, 0xcfef },
+       {/*1d*/ 1, 0xff61, 0x55b2, 0xaad3, 0x7914, 0x8675, 0x2ca6, 0xd3c7,
+          0x9e28, 0x6149, 0xcb9a, 0x34fb, 0xe73c, 0x185d, 0xb28e, 0x4def },
+       {/*1e*/ 1, 0x5451, 0xa8a2, 0xfcf3, 0x9694, 0xc2c5, 0x3e36, 0x6a67,
+          0xebe8, 0xbfb9, 0x434a, 0x171b, 0x7d7c, 0x292d, 0xd5de, 0x818f },
+       {/*1f*/ 1, 0x6fc1, 0xb542, 0xda83, 0x19f4, 0x7635, 0xacb6, 0xc377,
+          0x2e58, 0x4199, 0x9b1a, 0xf4db, 0x37ac, 0x586d, 0x82ee, 0xed2f },
+
+       /* ECC bits are also in the set of tokens and they too can go bad
+        * first 2 cover channel 0, while the second 2 cover channel 1
+        */
+       {/*20*/ 0, 0xbe01, 0xd702, 0x6903, 0x2104, 0x9f05, 0xf606, 0x4807,
+          0x3208, 0x8c09, 0xe50a, 0x5b0b, 0x130c, 0xad0d, 0xc40e, 0x7a0f },
+       {/*21*/ 0, 0x4101, 0x8202, 0xc303, 0x5804, 0x1905, 0xda06, 0x9b07,
+          0xac08, 0xed09, 0x2e0a, 0x6f0b, 0x640c, 0xb50d, 0x760e, 0x370f },
+       {/*22*/ 1, 0xc441, 0x4882, 0x8cc3, 0xf654, 0x3215, 0xbed6, 0x7a97,
+          0x5ba8, 0x9fe9, 0x132a, 0xd76b, 0xadfc, 0x69bd, 0xe57e, 0x213f },
+       {/*23*/ 1, 0x7621, 0x9b32, 0xed13, 0xda44, 0xac65, 0x4176, 0x3757,
+          0x6f88, 0x19a9, 0xf4ba, 0x829b, 0xb5cc, 0xc3ed, 0x2efe, 0x58df }
+};
+
+/*
+ * Given the syndrome argument, scan each of the channel tables for a syndrome
+ * match. Depending on which table it is found, return the channel number.
+ */
+static int get_channel_from_ecc_syndrome(unsigned short syndrome)
+{
+       int row;
+       int column;
+
+       /* Determine column to scan */
+       column = syndrome & 0xF;
+
+       /* Scan all rows, looking for syndrome, or end of table */
+       for (row = 0; row < NUMBER_ECC_ROWS; row++) {
+               if (ecc_chipkill_syndromes[row][column] == syndrome)
+                       return ecc_chipkill_syndromes[row][0];
+       }
+
+       debugf0("syndrome(%x) not found\n", syndrome);
+       return -1;
+}
+
+/*
+ * Check for valid error in the NB Status High register. If so, proceed to read
+ * NB Status Low, NB Address Low and NB Address High registers and store data
+ * into error structure.
+ *
+ * Returns:
+ *     - 1: if hardware regs contains valid error info
+ *     - 0: if no valid error is indicated
+ */
+static int amd64_get_error_info_regs(struct mem_ctl_info *mci,
+                                    struct amd64_error_info_regs *regs)
+{
+       struct amd64_pvt *pvt;
+       struct pci_dev *misc_f3_ctl;
+       int err = 0;
+
+       pvt = mci->pvt_info;
+       misc_f3_ctl = pvt->misc_f3_ctl;
+
+       err = pci_read_config_dword(misc_f3_ctl, K8_NBSH, &regs->nbsh);
+       if (err)
+               goto err_reg;
+
+       if (!(regs->nbsh & K8_NBSH_VALID_BIT))
+               return 0;
+
+       /* valid error, read remaining error information registers */
+       err = pci_read_config_dword(misc_f3_ctl, K8_NBSL, &regs->nbsl);
+       if (err)
+               goto err_reg;
+
+       err = pci_read_config_dword(misc_f3_ctl, K8_NBEAL, &regs->nbeal);
+       if (err)
+               goto err_reg;
+
+       err = pci_read_config_dword(misc_f3_ctl, K8_NBEAH, &regs->nbeah);
+       if (err)
+               goto err_reg;
+
+       err = pci_read_config_dword(misc_f3_ctl, K8_NBCFG, &regs->nbcfg);
+       if (err)
+               goto err_reg;
+
+       return 1;
+
+err_reg:
+       debugf0("Reading error info register failed\n");
+       return 0;
+}
+
+/*
+ * This function is called to retrieve the error data from hardware and store it
+ * in the info structure.
+ *
+ * Returns:
+ *     - 1: if a valid error is found
+ *     - 0: if no error is found
+ */
+static int amd64_get_error_info(struct mem_ctl_info *mci,
+                               struct amd64_error_info_regs *info)
+{
+       struct amd64_pvt *pvt;
+       struct amd64_error_info_regs regs;
+
+       pvt = mci->pvt_info;
+
+       if (!amd64_get_error_info_regs(mci, info))
+               return 0;
+
+       /*
+        * Here's the problem with the K8's EDAC reporting: There are four
+        * registers which report pieces of error information. They are shared
+        * between CEs and UEs. Furthermore, contrary to what is stated in the
+        * BKDG, the overflow bit is never used! Every error always updates the
+        * reporting registers.
+        *
+        * Can you see the race condition? All four error reporting registers
+        * must be read before a new error updates them! There is no way to read
+        * all four registers atomically. The best than can be done is to detect
+        * that a race has occured and then report the error without any kind of
+        * precision.
+        *
+        * What is still positive is that errors are still reported and thus
+        * problems can still be detected - just not localized because the
+        * syndrome and address are spread out across registers.
+        *
+        * Grrrrr!!!!!  Here's hoping that AMD fixes this in some future K8 rev.
+        * UEs and CEs should have separate register sets with proper overflow
+        * bits that are used! At very least the problem can be fixed by
+        * honoring the ErrValid bit in 'nbsh' and not updating registers - just
+        * set the overflow bit - unless the current error is CE and the new
+        * error is UE which would be the only situation for overwriting the
+        * current values.
+        */
+
+       regs = *info;
+
+       /* Use info from the second read - most current */
+       if (unlikely(!amd64_get_error_info_regs(mci, info)))
+               return 0;
+
+       /* clear the error bits in hardware */
+       pci_write_bits32(pvt->misc_f3_ctl, K8_NBSH, 0, K8_NBSH_VALID_BIT);
+
+       /* Check for the possible race condition */
+       if ((regs.nbsh != info->nbsh) ||
+            (regs.nbsl != info->nbsl) ||
+            (regs.nbeah != info->nbeah) ||
+            (regs.nbeal != info->nbeal)) {
+               amd64_mc_printk(mci, KERN_WARNING,
+                               "hardware STATUS read access race condition "
+                               "detected!\n");
+               return 0;
+       }
+       return 1;
+}
+
+static inline void amd64_decode_gart_tlb_error(struct mem_ctl_info *mci,
+                                        struct amd64_error_info_regs *info)
+{
+       u32 err_code;
+       u32 ec_tt;              /* error code transaction type (2b) */
+       u32 ec_ll;              /* error code cache level (2b) */
+
+       err_code = EXTRACT_ERROR_CODE(info->nbsl);
+       ec_ll = EXTRACT_LL_CODE(err_code);
+       ec_tt = EXTRACT_TT_CODE(err_code);
+
+       amd64_mc_printk(mci, KERN_ERR,
+                    "GART TLB event: transaction type(%s), "
+                    "cache level(%s)\n", tt_msgs[ec_tt], ll_msgs[ec_ll]);
+}
+
+static inline void amd64_decode_mem_cache_error(struct mem_ctl_info *mci,
+                                     struct amd64_error_info_regs *info)
+{
+       u32 err_code;
+       u32 ec_rrrr;            /* error code memory transaction (4b) */
+       u32 ec_tt;              /* error code transaction type (2b) */
+       u32 ec_ll;              /* error code cache level (2b) */
+
+       err_code = EXTRACT_ERROR_CODE(info->nbsl);
+       ec_ll = EXTRACT_LL_CODE(err_code);
+       ec_tt = EXTRACT_TT_CODE(err_code);
+       ec_rrrr = EXTRACT_RRRR_CODE(err_code);
+
+       amd64_mc_printk(mci, KERN_ERR,
+                    "cache hierarchy error: memory transaction type(%s), "
+                    "transaction type(%s), cache level(%s)\n",
+                    rrrr_msgs[ec_rrrr], tt_msgs[ec_tt], ll_msgs[ec_ll]);
+}
+
+
+/*
+ * Handle any Correctable Errors (CEs) that have occurred. Check for valid ERROR
+ * ADDRESS and process.
+ */
+static void amd64_handle_ce(struct mem_ctl_info *mci,
+                           struct amd64_error_info_regs *info)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       u64 SystemAddress;
+
+       /* Ensure that the Error Address is VALID */
+       if ((info->nbsh & K8_NBSH_VALID_ERROR_ADDR) == 0) {
+               amd64_mc_printk(mci, KERN_ERR,
+                       "HW has no ERROR_ADDRESS available\n");
+               edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
+               return;
+       }
+
+       SystemAddress = extract_error_address(mci, info);
+
+       amd64_mc_printk(mci, KERN_ERR,
+               "CE ERROR_ADDRESS= 0x%llx\n", SystemAddress);
+
+       pvt->ops->map_sysaddr_to_csrow(mci, info, SystemAddress);
+}
+
+/* Handle any Un-correctable Errors (UEs) */
+static void amd64_handle_ue(struct mem_ctl_info *mci,
+                           struct amd64_error_info_regs *info)
+{
+       int csrow;
+       u64 SystemAddress;
+       u32 page, offset;
+       struct mem_ctl_info *log_mci, *src_mci = NULL;
+
+       log_mci = mci;
+
+       if ((info->nbsh & K8_NBSH_VALID_ERROR_ADDR) == 0) {
+               amd64_mc_printk(mci, KERN_CRIT,
+                       "HW has no ERROR_ADDRESS available\n");
+               edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
+               return;
+       }
+
+       SystemAddress = extract_error_address(mci, info);
+
+       /*
+        * Find out which node the error address belongs to. This may be
+        * different from the node that detected the error.
+        */
+       src_mci = find_mc_by_sys_addr(mci, SystemAddress);
+       if (!src_mci) {
+               amd64_mc_printk(mci, KERN_CRIT,
+                       "ERROR ADDRESS (0x%lx) value NOT mapped to a MC\n",
+                       (unsigned long)SystemAddress);
+               edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
+               return;
+       }
+
+       log_mci = src_mci;
+
+       csrow = sys_addr_to_csrow(log_mci, SystemAddress);
+       if (csrow < 0) {
+               amd64_mc_printk(mci, KERN_CRIT,
+                       "ERROR_ADDRESS (0x%lx) value NOT mapped to 'csrow'\n",
+                       (unsigned long)SystemAddress);
+               edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
+       } else {
+               error_address_to_page_and_offset(SystemAddress, &page, &offset);
+               edac_mc_handle_ue(log_mci, page, offset, csrow, EDAC_MOD_STR);
+       }
+}
+
+static void amd64_decode_bus_error(struct mem_ctl_info *mci,
+                                  struct amd64_error_info_regs *info)
+{
+       u32 err_code, ext_ec;
+       u32 ec_pp;              /* error code participating processor (2p) */
+       u32 ec_to;              /* error code timed out (1b) */
+       u32 ec_rrrr;            /* error code memory transaction (4b) */
+       u32 ec_ii;              /* error code memory or I/O (2b) */
+       u32 ec_ll;              /* error code cache level (2b) */
+
+       ext_ec = EXTRACT_EXT_ERROR_CODE(info->nbsl);
+       err_code = EXTRACT_ERROR_CODE(info->nbsl);
+
+       ec_ll = EXTRACT_LL_CODE(err_code);
+       ec_ii = EXTRACT_II_CODE(err_code);
+       ec_rrrr = EXTRACT_RRRR_CODE(err_code);
+       ec_to = EXTRACT_TO_CODE(err_code);
+       ec_pp = EXTRACT_PP_CODE(err_code);
+
+       amd64_mc_printk(mci, KERN_ERR,
+               "BUS ERROR:\n"
+               "  time-out(%s) mem or i/o(%s)\n"
+               "  participating processor(%s)\n"
+               "  memory transaction type(%s)\n"
+               "  cache level(%s) Error Found by: %s\n",
+               to_msgs[ec_to],
+               ii_msgs[ec_ii],
+               pp_msgs[ec_pp],
+               rrrr_msgs[ec_rrrr],
+               ll_msgs[ec_ll],
+               (info->nbsh & K8_NBSH_ERR_SCRUBER) ?
+                       "Scrubber" : "Normal Operation");
+
+       /* If this was an 'observed' error, early out */
+       if (ec_pp == K8_NBSL_PP_OBS)
+               return;         /* We aren't the node involved */
+
+       /* Parse out the extended error code for ECC events */
+       switch (ext_ec) {
+       /* F10 changed to one Extended ECC error code */
+       case F10_NBSL_EXT_ERR_RES:              /* Reserved field */
+       case F10_NBSL_EXT_ERR_ECC:              /* F10 ECC ext err code */
+               break;
+
+       default:
+               amd64_mc_printk(mci, KERN_ERR, "NOT ECC: no special error "
+                                              "handling for this error\n");
+               return;
+       }
+
+       if (info->nbsh & K8_NBSH_CECC)
+               amd64_handle_ce(mci, info);
+       else if (info->nbsh & K8_NBSH_UECC)
+               amd64_handle_ue(mci, info);
+
+       /*
+        * If main error is CE then overflow must be CE.  If main error is UE
+        * then overflow is unknown.  We'll call the overflow a CE - if
+        * panic_on_ue is set then we're already panic'ed and won't arrive
+        * here. Else, then apparently someone doesn't think that UE's are
+        * catastrophic.
+        */
+       if (info->nbsh & K8_NBSH_OVERFLOW)
+               edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR
+                                         "Error Overflow set");
+}
+
+int amd64_process_error_info(struct mem_ctl_info *mci,
+                            struct amd64_error_info_regs *info,
+                            int handle_errors)
+{
+       struct amd64_pvt *pvt;
+       struct amd64_error_info_regs *regs;
+       u32 err_code, ext_ec;
+       int gart_tlb_error = 0;
+
+       pvt = mci->pvt_info;
+
+       /* If caller doesn't want us to process the error, return */
+       if (!handle_errors)
+               return 1;
+
+       regs = info;
+
+       debugf1("NorthBridge ERROR: mci(0x%p)\n", mci);
+       debugf1("  MC node(%d) Error-Address(0x%.8x-%.8x)\n",
+               pvt->mc_node_id, regs->nbeah, regs->nbeal);
+       debugf1("  nbsh(0x%.8x) nbsl(0x%.8x)\n",
+               regs->nbsh, regs->nbsl);
+       debugf1("  Valid Error=%s Overflow=%s\n",
+               (regs->nbsh & K8_NBSH_VALID_BIT) ? "True" : "False",
+               (regs->nbsh & K8_NBSH_OVERFLOW) ? "True" : "False");
+       debugf1("  Err Uncorrected=%s MCA Error Reporting=%s\n",
+               (regs->nbsh & K8_NBSH_UNCORRECTED_ERR) ?
+                       "True" : "False",
+               (regs->nbsh & K8_NBSH_ERR_ENABLE) ?
+                       "True" : "False");
+       debugf1("  MiscErr Valid=%s ErrAddr Valid=%s PCC=%s\n",
+               (regs->nbsh & K8_NBSH_MISC_ERR_VALID) ?
+                       "True" : "False",
+               (regs->nbsh & K8_NBSH_VALID_ERROR_ADDR) ?
+                       "True" : "False",
+               (regs->nbsh & K8_NBSH_PCC) ?
+                       "True" : "False");
+       debugf1("  CECC=%s UECC=%s Found by Scruber=%s\n",
+               (regs->nbsh & K8_NBSH_CECC) ?
+                       "True" : "False",
+               (regs->nbsh & K8_NBSH_UECC) ?
+                       "True" : "False",
+               (regs->nbsh & K8_NBSH_ERR_SCRUBER) ?
+                       "True" : "False");
+       debugf1("  CORE0=%s CORE1=%s CORE2=%s CORE3=%s\n",
+               (regs->nbsh & K8_NBSH_CORE0) ? "True" : "False",
+               (regs->nbsh & K8_NBSH_CORE1) ? "True" : "False",
+               (regs->nbsh & K8_NBSH_CORE2) ? "True" : "False",
+               (regs->nbsh & K8_NBSH_CORE3) ? "True" : "False");
+
+
+       err_code = EXTRACT_ERROR_CODE(regs->nbsl);
+
+       /* Determine which error type:
+        *      1) GART errors - non-fatal, developmental events
+        *      2) MEMORY errors
+        *      3) BUS errors
+        *      4) Unknown error
+        */
+       if (TEST_TLB_ERROR(err_code)) {
+               /*
+                * GART errors are intended to help graphics driver developers
+                * to detect bad GART PTEs. It is recommended by AMD to disable
+                * GART table walk error reporting by default[1] (currently
+                * being disabled in mce_cpu_quirks()) and according to the
+                * comment in mce_cpu_quirks(), such GART errors can be
+                * incorrectly triggered. We may see these errors anyway and
+                * unless requested by the user, they won't be reported.
+                *
+                * [1] section 13.10.1 on BIOS and Kernel Developers Guide for
+                *     AMD NPT family 0Fh processors
+                */
+               if (report_gart_errors == 0)
+                       return 1;
+
+               /*
+                * Only if GART error reporting is requested should we generate
+                * any logs.
+                */
+               gart_tlb_error = 1;
+
+               debugf1("GART TLB error\n");
+               amd64_decode_gart_tlb_error(mci, info);
+       } else if (TEST_MEM_ERROR(err_code)) {
+               debugf1("Memory/Cache error\n");
+               amd64_decode_mem_cache_error(mci, info);
+       } else if (TEST_BUS_ERROR(err_code)) {
+               debugf1("Bus (Link/DRAM) error\n");
+               amd64_decode_bus_error(mci, info);
+       } else {
+               /* shouldn't reach here! */
+               amd64_mc_printk(mci, KERN_WARNING,
+                            "%s(): unknown MCE error 0x%x\n", __func__,
+                            err_code);
+       }
+
+       ext_ec = EXTRACT_EXT_ERROR_CODE(regs->nbsl);
+       amd64_mc_printk(mci, KERN_ERR,
+               "ExtErr=(0x%x) %s\n", ext_ec, ext_msgs[ext_ec]);
+
+       if (((ext_ec >= F10_NBSL_EXT_ERR_CRC &&
+                       ext_ec <= F10_NBSL_EXT_ERR_TGT) ||
+                       (ext_ec == F10_NBSL_EXT_ERR_RMW)) &&
+                       EXTRACT_LDT_LINK(info->nbsh)) {
+
+               amd64_mc_printk(mci, KERN_ERR,
+                       "Error on hypertransport link: %s\n",
+                       htlink_msgs[
+                       EXTRACT_LDT_LINK(info->nbsh)]);
+       }
+
+       /*
+        * Check the UE bit of the NB status high register, if set generate some
+        * logs. If NOT a GART error, then process the event as a NO-INFO event.
+        * If it was a GART error, skip that process.
+        */
+       if (regs->nbsh & K8_NBSH_UNCORRECTED_ERR) {
+               amd64_mc_printk(mci, KERN_CRIT, "uncorrected error\n");
+               if (!gart_tlb_error)
+                       edac_mc_handle_ue_no_info(mci, "UE bit is set\n");
+       }
+
+       if (regs->nbsh & K8_NBSH_PCC)
+               amd64_mc_printk(mci, KERN_CRIT,
+                       "PCC (processor context corrupt) set\n");
+
+       return 1;
+}
+EXPORT_SYMBOL_GPL(amd64_process_error_info);
+
+/*
+ * The main polling 'check' function, called FROM the edac core to perform the
+ * error checking and if an error is encountered, error processing.
+ */
+static void amd64_check(struct mem_ctl_info *mci)
+{
+       struct amd64_error_info_regs info;
+
+       if (amd64_get_error_info(mci, &info))
+               amd64_process_error_info(mci, &info, 1);
+}
+
+/*
+ * Input:
+ *     1) struct amd64_pvt which contains pvt->dram_f2_ctl pointer
+ *     2) AMD Family index value
+ *
+ * Ouput:
+ *     Upon return of 0, the following filled in:
+ *
+ *             struct pvt->addr_f1_ctl
+ *             struct pvt->misc_f3_ctl
+ *
+ *     Filled in with related device funcitions of 'dram_f2_ctl'
+ *     These devices are "reserved" via the pci_get_device()
+ *
+ *     Upon return of 1 (error status):
+ *
+ *             Nothing reserved
+ */
+static int amd64_reserve_mc_sibling_devices(struct amd64_pvt *pvt, int mc_idx)
+{
+       const struct amd64_family_type *amd64_dev = &amd64_family_types[mc_idx];
+
+       /* Reserve the ADDRESS MAP Device */
+       pvt->addr_f1_ctl = pci_get_related_function(pvt->dram_f2_ctl->vendor,
+                                                   amd64_dev->addr_f1_ctl,
+                                                   pvt->dram_f2_ctl);
+
+       if (!pvt->addr_f1_ctl) {
+               amd64_printk(KERN_ERR, "error address map device not found: "
+                            "vendor %x device 0x%x (broken BIOS?)\n",
+                            PCI_VENDOR_ID_AMD, amd64_dev->addr_f1_ctl);
+               return 1;
+       }
+
+       /* Reserve the MISC Device */
+       pvt->misc_f3_ctl = pci_get_related_function(pvt->dram_f2_ctl->vendor,
+                                                   amd64_dev->misc_f3_ctl,
+                                                   pvt->dram_f2_ctl);
+
+       if (!pvt->misc_f3_ctl) {
+               pci_dev_put(pvt->addr_f1_ctl);
+               pvt->addr_f1_ctl = NULL;
+
+               amd64_printk(KERN_ERR, "error miscellaneous device not found: "
+                            "vendor %x device 0x%x (broken BIOS?)\n",
+                            PCI_VENDOR_ID_AMD, amd64_dev->misc_f3_ctl);
+               return 1;
+       }
+
+       debugf1("    Addr Map device PCI Bus ID:\t%s\n",
+               pci_name(pvt->addr_f1_ctl));
+       debugf1("    DRAM MEM-CTL PCI Bus ID:\t%s\n",
+               pci_name(pvt->dram_f2_ctl));
+       debugf1("    Misc device PCI Bus ID:\t%s\n",
+               pci_name(pvt->misc_f3_ctl));
+
+       return 0;
+}
+
+static void amd64_free_mc_sibling_devices(struct amd64_pvt *pvt)
+{
+       pci_dev_put(pvt->addr_f1_ctl);
+       pci_dev_put(pvt->misc_f3_ctl);
+}
+
+/*
+ * Retrieve the hardware registers of the memory controller (this includes the
+ * 'Address Map' and 'Misc' device regs)
+ */
+static void amd64_read_mc_registers(struct amd64_pvt *pvt)
+{
+       u64 msr_val;
+       int dram, err = 0;
+
+       /*
+        * Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since
+        * those are Read-As-Zero
+        */
+       rdmsrl(MSR_K8_TOP_MEM1, msr_val);
+       pvt->top_mem = msr_val >> 23;
+       debugf0("  TOP_MEM=0x%08llx\n", pvt->top_mem);
+
+       /* check first whether TOP_MEM2 is enabled */
+       rdmsrl(MSR_K8_SYSCFG, msr_val);
+       if (msr_val & (1U << 21)) {
+               rdmsrl(MSR_K8_TOP_MEM2, msr_val);
+               pvt->top_mem2 = msr_val >> 23;
+               debugf0("  TOP_MEM2=0x%08llx\n", pvt->top_mem2);
+       } else
+               debugf0("  TOP_MEM2 disabled.\n");
+
+       amd64_cpu_display_info(pvt);
+
+       err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCAP, &pvt->nbcap);
+       if (err)
+               goto err_reg;
+
+       if (pvt->ops->read_dram_ctl_register)
+               pvt->ops->read_dram_ctl_register(pvt);
+
+       for (dram = 0; dram < DRAM_REG_COUNT; dram++) {
+               /*
+                * Call CPU specific READ function to get the DRAM Base and
+                * Limit values from the DCT.
+                */
+               pvt->ops->read_dram_base_limit(pvt, dram);
+
+               /*
+                * Only print out debug info on rows with both R and W Enabled.
+                * Normal processing, compiler should optimize this whole 'if'
+                * debug output block away.
+                */
+               if (pvt->dram_rw_en[dram] != 0) {
+                       debugf1("  DRAM_BASE[%d]: 0x%8.08x-%8.08x "
+                               "DRAM_LIMIT:  0x%8.08x-%8.08x\n",
+                               dram,
+                               (u32)(pvt->dram_base[dram] >> 32),
+                               (u32)(pvt->dram_base[dram] & 0xFFFFFFFF),
+                               (u32)(pvt->dram_limit[dram] >> 32),
+                               (u32)(pvt->dram_limit[dram] & 0xFFFFFFFF));
+                       debugf1("        IntlvEn=%s %s %s "
+                               "IntlvSel=%d DstNode=%d\n",
+                               pvt->dram_IntlvEn[dram] ?
+                                       "Enabled" : "Disabled",
+                               (pvt->dram_rw_en[dram] & 0x2) ? "W" : "!W",
+                               (pvt->dram_rw_en[dram] & 0x1) ? "R" : "!R",
+                               pvt->dram_IntlvSel[dram],
+                               pvt->dram_DstNode[dram]);
+               }
+       }
+
+       amd64_read_dct_base_mask(pvt);
+
+       err = pci_read_config_dword(pvt->addr_f1_ctl, K8_DHAR, &pvt->dhar);
+       if (err)
+               goto err_reg;
+
+       amd64_read_dbam_reg(pvt);
+
+       err = pci_read_config_dword(pvt->misc_f3_ctl,
+                               F10_ONLINE_SPARE, &pvt->online_spare);
+       if (err)
+               goto err_reg;
+
+       err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCLR_0, &pvt->dclr0);
+       if (err)
+               goto err_reg;
+
+       err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCHR_0, &pvt->dchr0);
+       if (err)
+               goto err_reg;
+
+       if (!dct_ganging_enabled(pvt)) {
+               err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCLR_1,
+                                               &pvt->dclr1);
+               if (err)
+                       goto err_reg;
+
+               err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCHR_1,
+                                               &pvt->dchr1);
+               if (err)
+                       goto err_reg;
+       }
+
+       amd64_dump_misc_regs(pvt);
+
+err_reg:
+       debugf0("Reading an MC register failed\n");
+
+}
+
+/*
+ * NOTE: CPU Revision Dependent code
+ *
+ * Input:
+ *     @csrow_nr ChipSelect Row Number (0..CHIPSELECT_COUNT-1)
+ *     k8 private pointer to -->
+ *                     DRAM Bank Address mapping register
+ *                     node_id
+ *                     DCL register where dual_channel_active is
+ *
+ * The DBAM register consists of 4 sets of 4 bits each definitions:
+ *
+ * Bits:       CSROWs
+ * 0-3         CSROWs 0 and 1
+ * 4-7         CSROWs 2 and 3
+ * 8-11                CSROWs 4 and 5
+ * 12-15       CSROWs 6 and 7
+ *
+ * Values range from: 0 to 15
+ * The meaning of the values depends on CPU revision and dual-channel state,
+ * see relevant BKDG more info.
+ *
+ * The memory controller provides for total of only 8 CSROWs in its current
+ * architecture. Each "pair" of CSROWs normally represents just one DIMM in
+ * single channel or two (2) DIMMs in dual channel mode.
+ *
+ * The following code logic collapses the various tables for CSROW based on CPU
+ * revision.
+ *
+ * Returns:
+ *     The number of PAGE_SIZE pages on the specified CSROW number it
+ *     encompasses
+ *
+ */
+static u32 amd64_csrow_nr_pages(int csrow_nr, struct amd64_pvt *pvt)
+{
+       u32 dram_map, nr_pages;
+
+       /*
+        * The math on this doesn't look right on the surface because x/2*4 can
+        * be simplified to x*2 but this expression makes use of the fact that
+        * it is integral math where 1/2=0. This intermediate value becomes the
+        * number of bits to shift the DBAM register to extract the proper CSROW
+        * field.
+        */
+       dram_map = (pvt->dbam0 >> ((csrow_nr / 2) * 4)) & 0xF;
+
+       nr_pages = pvt->ops->dbam_map_to_pages(pvt, dram_map);
+
+       /*
+        * If dual channel then double the memory size of single channel.
+        * Channel count is 1 or 2
+        */
+       nr_pages <<= (pvt->channel_count - 1);
+
+       debugf0("  (csrow=%d) DBAM map index= %d\n", csrow_nr, dram_map);
+       debugf0("    nr_pages= %u  channel-count = %d\n",
+               nr_pages, pvt->channel_count);
+
+       return nr_pages;
+}
+
+/*
+ * Initialize the array of csrow attribute instances, based on the values
+ * from pci config hardware registers.
+ */
+static int amd64_init_csrows(struct mem_ctl_info *mci)
+{
+       struct csrow_info *csrow;
+       struct amd64_pvt *pvt;
+       u64 input_addr_min, input_addr_max, sys_addr;
+       int i, err = 0, empty = 1;
+
+       pvt = mci->pvt_info;
+
+       err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCFG, &pvt->nbcfg);
+       if (err)
+               debugf0("Reading K8_NBCFG failed\n");
+
+       debugf0("NBCFG= 0x%x  CHIPKILL= %s DRAM ECC= %s\n", pvt->nbcfg,
+               (pvt->nbcfg & K8_NBCFG_CHIPKILL) ? "Enabled" : "Disabled",
+               (pvt->nbcfg & K8_NBCFG_ECC_ENABLE) ? "Enabled" : "Disabled"
+               );
+
+       for (i = 0; i < CHIPSELECT_COUNT; i++) {
+               csrow = &mci->csrows[i];
+
+               if ((pvt->dcsb0[i] & K8_DCSB_CS_ENABLE) == 0) {
+                       debugf1("----CSROW %d EMPTY for node %d\n", i,
+                               pvt->mc_node_id);
+                       continue;
+               }
+
+               debugf1("----CSROW %d VALID for MC node %d\n",
+                       i, pvt->mc_node_id);
+
+               empty = 0;
+               csrow->nr_pages = amd64_csrow_nr_pages(i, pvt);
+               find_csrow_limits(mci, i, &input_addr_min, &input_addr_max);
+               sys_addr = input_addr_to_sys_addr(mci, input_addr_min);
+               csrow->first_page = (u32) (sys_addr >> PAGE_SHIFT);
+               sys_addr = input_addr_to_sys_addr(mci, input_addr_max);
+               csrow->last_page = (u32) (sys_addr >> PAGE_SHIFT);
+               csrow->page_mask = ~mask_from_dct_mask(pvt, i);
+               /* 8 bytes of resolution */
+
+               csrow->mtype = amd64_determine_memory_type(pvt);
+
+               debugf1("  for MC node %d csrow %d:\n", pvt->mc_node_id, i);
+               debugf1("    input_addr_min: 0x%lx input_addr_max: 0x%lx\n",
+                       (unsigned long)input_addr_min,
+                       (unsigned long)input_addr_max);
+               debugf1("    sys_addr: 0x%lx  page_mask: 0x%lx\n",
+                       (unsigned long)sys_addr, csrow->page_mask);
+               debugf1("    nr_pages: %u  first_page: 0x%lx "
+                       "last_page: 0x%lx\n",
+                       (unsigned)csrow->nr_pages,
+                       csrow->first_page, csrow->last_page);
+
+               /*
+                * determine whether CHIPKILL or JUST ECC or NO ECC is operating
+                */
+               if (pvt->nbcfg & K8_NBCFG_ECC_ENABLE)
+                       csrow->edac_mode =
+                           (pvt->nbcfg & K8_NBCFG_CHIPKILL) ?
+                           EDAC_S4ECD4ED : EDAC_SECDED;
+               else
+                       csrow->edac_mode = EDAC_NONE;
+       }
+
+       return empty;
+}
+
+/*
+ * Only if 'ecc_enable_override' is set AND BIOS had ECC disabled, do "we"
+ * enable it.
+ */
+static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       const cpumask_t *cpumask = cpumask_of_node(pvt->mc_node_id);
+       int cpu, idx = 0, err = 0;
+       struct msr msrs[cpumask_weight(cpumask)];
+       u32 value;
+       u32 mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn;
+
+       if (!ecc_enable_override)
+               return;
+
+       memset(msrs, 0, sizeof(msrs));
+
+       amd64_printk(KERN_WARNING,
+               "'ecc_enable_override' parameter is active, "
+               "Enabling AMD ECC hardware now: CAUTION\n");
+
+       err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCTL, &value);
+       if (err)
+               debugf0("Reading K8_NBCTL failed\n");
+
+       /* turn on UECCn and CECCEn bits */
+       pvt->old_nbctl = value & mask;
+       pvt->nbctl_mcgctl_saved = 1;
+
+       value |= mask;
+       pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value);
+
+       rdmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs);
+
+       for_each_cpu(cpu, cpumask) {
+               if (msrs[idx].l & K8_MSR_MCGCTL_NBE)
+                       set_bit(idx, &pvt->old_mcgctl);
+
+               msrs[idx].l |= K8_MSR_MCGCTL_NBE;
+               idx++;
+       }
+       wrmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs);
+
+       err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCFG, &value);
+       if (err)
+               debugf0("Reading K8_NBCFG failed\n");
+
+       debugf0("NBCFG(1)= 0x%x  CHIPKILL= %s ECC_ENABLE= %s\n", value,
+               (value & K8_NBCFG_CHIPKILL) ? "Enabled" : "Disabled",
+               (value & K8_NBCFG_ECC_ENABLE) ? "Enabled" : "Disabled");
+
+       if (!(value & K8_NBCFG_ECC_ENABLE)) {
+               amd64_printk(KERN_WARNING,
+                       "This node reports that DRAM ECC is "
+                       "currently Disabled; ENABLING now\n");
+
+               /* Attempt to turn on DRAM ECC Enable */
+               value |= K8_NBCFG_ECC_ENABLE;
+               pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCFG, value);
+
+               err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCFG, &value);
+               if (err)
+                       debugf0("Reading K8_NBCFG failed\n");
+
+               if (!(value & K8_NBCFG_ECC_ENABLE)) {
+                       amd64_printk(KERN_WARNING,
+                               "Hardware rejects Enabling DRAM ECC checking\n"
+                               "Check memory DIMM configuration\n");
+               } else {
+                       amd64_printk(KERN_DEBUG,
+                               "Hardware accepted DRAM ECC Enable\n");
+               }
+       }
+       debugf0("NBCFG(2)= 0x%x  CHIPKILL= %s ECC_ENABLE= %s\n", value,
+               (value & K8_NBCFG_CHIPKILL) ? "Enabled" : "Disabled",
+               (value & K8_NBCFG_ECC_ENABLE) ? "Enabled" : "Disabled");
+
+       pvt->ctl_error_info.nbcfg = value;
+}
+
+static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt)
+{
+       const cpumask_t *cpumask = cpumask_of_node(pvt->mc_node_id);
+       int cpu, idx = 0, err = 0;
+       struct msr msrs[cpumask_weight(cpumask)];
+       u32 value;
+       u32 mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn;
+
+       if (!pvt->nbctl_mcgctl_saved)
+               return;
+
+       memset(msrs, 0, sizeof(msrs));
+
+       err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCTL, &value);
+       if (err)
+               debugf0("Reading K8_NBCTL failed\n");
+       value &= ~mask;
+       value |= pvt->old_nbctl;
+
+       /* restore the NB Enable MCGCTL bit */
+       pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value);
+
+       rdmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs);
+
+       for_each_cpu(cpu, cpumask) {
+               msrs[idx].l &= ~K8_MSR_MCGCTL_NBE;
+               msrs[idx].l |=
+                       test_bit(idx, &pvt->old_mcgctl) << K8_MSR_MCGCTL_NBE;
+               idx++;
+       }
+
+       wrmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs);
+}
+
+static void check_mcg_ctl(void *ret)
+{
+       u64 msr_val = 0;
+       u8 nbe;
+
+       rdmsrl(MSR_IA32_MCG_CTL, msr_val);
+       nbe = msr_val & K8_MSR_MCGCTL_NBE;
+
+       debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
+               raw_smp_processor_id(), msr_val,
+               (nbe ? "enabled" : "disabled"));
+
+       if (!nbe)
+               *(int *)ret = 0;
+}
+
+/* check MCG_CTL on all the cpus on this node */
+static int amd64_mcg_ctl_enabled_on_cpus(const cpumask_t *mask)
+{
+       int ret = 1;
+       preempt_disable();
+       smp_call_function_many(mask, check_mcg_ctl, &ret, 1);
+       preempt_enable();
+
+       return ret;
+}
+
+/*
+ * EDAC requires that the BIOS have ECC enabled before taking over the
+ * processing of ECC errors. This is because the BIOS can properly initialize
+ * the memory system completely. A command line option allows to force-enable
+ * hardware ECC later in amd64_enable_ecc_error_reporting().
+ */
+static int amd64_check_ecc_enabled(struct amd64_pvt *pvt)
+{
+       u32 value;
+       int err = 0, ret = 0;
+       u8 ecc_enabled = 0;
+
+       err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCFG, &value);
+       if (err)
+               debugf0("Reading K8_NBCTL failed\n");
+
+       ecc_enabled = !!(value & K8_NBCFG_ECC_ENABLE);
+
+       ret = amd64_mcg_ctl_enabled_on_cpus(cpumask_of_node(pvt->mc_node_id));
+
+       debugf0("K8_NBCFG=0x%x,  DRAM ECC is %s\n", value,
+                       (value & K8_NBCFG_ECC_ENABLE ? "enabled" : "disabled"));
+
+       if (!ecc_enabled || !ret) {
+               if (!ecc_enabled) {
+                       amd64_printk(KERN_WARNING, "This node reports that "
+                                                  "Memory ECC is currently "
+                                                  "disabled.\n");
+
+                       amd64_printk(KERN_WARNING, "bit 0x%lx in register "
+                               "F3x%x of the MISC_CONTROL device (%s) "
+                               "should be enabled\n", K8_NBCFG_ECC_ENABLE,
+                               K8_NBCFG, pci_name(pvt->misc_f3_ctl));
+               }
+               if (!ret) {
+                       amd64_printk(KERN_WARNING, "bit 0x%016lx in MSR 0x%08x "
+                                       "of node %d should be enabled\n",
+                                       K8_MSR_MCGCTL_NBE, MSR_IA32_MCG_CTL,
+                                       pvt->mc_node_id);
+               }
+               if (!ecc_enable_override) {
+                       amd64_printk(KERN_WARNING, "WARNING: ECC is NOT "
+                               "currently enabled by the BIOS. Module "
+                               "will NOT be loaded.\n"
+                               "    Either Enable ECC in the BIOS, "
+                               "or use the 'ecc_enable_override' "
+                               "parameter.\n"
+                               "    Might be a BIOS bug, if BIOS says "
+                               "ECC is enabled\n"
+                               "    Use of the override can cause "
+                               "unknown side effects.\n");
+                       ret = -ENODEV;
+               }
+       } else {
+               amd64_printk(KERN_INFO,
+                       "ECC is enabled by BIOS, Proceeding "
+                       "with EDAC module initialization\n");
+
+               /* CLEAR the override, since BIOS controlled it */
+               ecc_enable_override = 0;
+       }
+
+       return ret;
+}
+
+struct mcidev_sysfs_attribute sysfs_attrs[ARRAY_SIZE(amd64_dbg_attrs) +
+                                         ARRAY_SIZE(amd64_inj_attrs) +
+                                         1];
+
+struct mcidev_sysfs_attribute terminator = { .attr = { .name = NULL } };
+
+static void amd64_set_mc_sysfs_attributes(struct mem_ctl_info *mci)
+{
+       unsigned int i = 0, j = 0;
+
+       for (; i < ARRAY_SIZE(amd64_dbg_attrs); i++)
+               sysfs_attrs[i] = amd64_dbg_attrs[i];
+
+       for (j = 0; j < ARRAY_SIZE(amd64_inj_attrs); j++, i++)
+               sysfs_attrs[i] = amd64_inj_attrs[j];
+
+       sysfs_attrs[i] = terminator;
+
+       mci->mc_driver_sysfs_attributes = sysfs_attrs;
+}
+
+static void amd64_setup_mci_misc_attributes(struct mem_ctl_info *mci)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+
+       mci->mtype_cap          = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2;
+       mci->edac_ctl_cap       = EDAC_FLAG_NONE;
+       mci->edac_cap           = EDAC_FLAG_NONE;
+
+       if (pvt->nbcap & K8_NBCAP_SECDED)
+               mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
+
+       if (pvt->nbcap & K8_NBCAP_CHIPKILL)
+               mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
+
+       mci->edac_cap           = amd64_determine_edac_cap(pvt);
+       mci->mod_name           = EDAC_MOD_STR;
+       mci->mod_ver            = EDAC_AMD64_VERSION;
+       mci->ctl_name           = get_amd_family_name(pvt->mc_type_index);
+       mci->dev_name           = pci_name(pvt->dram_f2_ctl);
+       mci->ctl_page_to_phys   = NULL;
+
+       /* IMPORTANT: Set the polling 'check' function in this module */
+       mci->edac_check         = amd64_check;
+
+       /* memory scrubber interface */
+       mci->set_sdram_scrub_rate = amd64_set_scrub_rate;
+       mci->get_sdram_scrub_rate = amd64_get_scrub_rate;
+}
+
+/*
+ * Init stuff for this DRAM Controller device.
+ *
+ * Due to a hardware feature on Fam10h CPUs, the Enable Extended Configuration
+ * Space feature MUST be enabled on ALL Processors prior to actually reading
+ * from the ECS registers. Since the loading of the module can occur on any
+ * 'core', and cores don't 'see' all the other processors ECS data when the
+ * others are NOT enabled. Our solution is to first enable ECS access in this
+ * routine on all processors, gather some data in a amd64_pvt structure and
+ * later come back in a finish-setup function to perform that final
+ * initialization. See also amd64_init_2nd_stage() for that.
+ */
+static int amd64_probe_one_instance(struct pci_dev *dram_f2_ctl,
+                                   int mc_type_index)
+{
+       struct amd64_pvt *pvt = NULL;
+       int err = 0, ret;
+
+       ret = -ENOMEM;
+       pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
+       if (!pvt)
+               goto err_exit;
+
+       pvt->mc_node_id = get_mc_node_id_from_pdev(dram_f2_ctl);
+
+       pvt->dram_f2_ctl        = dram_f2_ctl;
+       pvt->ext_model          = boot_cpu_data.x86_model >> 4;
+       pvt->mc_type_index      = mc_type_index;
+       pvt->ops                = family_ops(mc_type_index);
+       pvt->old_mcgctl         = 0;
+
+       /*
+        * We have the dram_f2_ctl device as an argument, now go reserve its
+        * sibling devices from the PCI system.
+        */
+       ret = -ENODEV;
+       err = amd64_reserve_mc_sibling_devices(pvt, mc_type_index);
+       if (err)
+               goto err_free;
+
+       ret = -EINVAL;
+       err = amd64_check_ecc_enabled(pvt);
+       if (err)
+               goto err_put;
+
+       /*
+        * Key operation here: setup of HW prior to performing ops on it. Some
+        * setup is required to access ECS data. After this is performed, the
+        * 'teardown' function must be called upon error and normal exit paths.
+        */
+       if (boot_cpu_data.x86 >= 0x10)
+               amd64_setup(pvt);
+
+       /*
+        * Save the pointer to the private data for use in 2nd initialization
+        * stage
+        */
+       pvt_lookup[pvt->mc_node_id] = pvt;
+
+       return 0;
+
+err_put:
+       amd64_free_mc_sibling_devices(pvt);
+
+err_free:
+       kfree(pvt);
+
+err_exit:
+       return ret;
+}
+
+/*
+ * This is the finishing stage of the init code. Needs to be performed after all
+ * MCs' hardware have been prepped for accessing extended config space.
+ */
+static int amd64_init_2nd_stage(struct amd64_pvt *pvt)
+{
+       int node_id = pvt->mc_node_id;
+       struct mem_ctl_info *mci;
+       int ret, err = 0;
+
+       amd64_read_mc_registers(pvt);
+
+       ret = -ENODEV;
+       if (pvt->ops->probe_valid_hardware) {
+               err = pvt->ops->probe_valid_hardware(pvt);
+               if (err)
+                       goto err_exit;
+       }
+
+       /*
+        * We need to determine how many memory channels there are. Then use
+        * that information for calculating the size of the dynamic instance
+        * tables in the 'mci' structure
+        */
+       pvt->channel_count = pvt->ops->early_channel_count(pvt);
+       if (pvt->channel_count < 0)
+               goto err_exit;
+
+       ret = -ENOMEM;
+       mci = edac_mc_alloc(0, CHIPSELECT_COUNT, pvt->channel_count, node_id);
+       if (!mci)
+               goto err_exit;
+
+       mci->pvt_info = pvt;
+
+       mci->dev = &pvt->dram_f2_ctl->dev;
+       amd64_setup_mci_misc_attributes(mci);
+
+       if (amd64_init_csrows(mci))
+               mci->edac_cap = EDAC_FLAG_NONE;
+
+       amd64_enable_ecc_error_reporting(mci);
+       amd64_set_mc_sysfs_attributes(mci);
+
+       ret = -ENODEV;
+       if (edac_mc_add_mc(mci)) {
+               debugf1("failed edac_mc_add_mc()\n");
+               goto err_add_mc;
+       }
+
+       mci_lookup[node_id] = mci;
+       pvt_lookup[node_id] = NULL;
+       return 0;
+
+err_add_mc:
+       edac_mc_free(mci);
+
+err_exit:
+       debugf0("failure to init 2nd stage: ret=%d\n", ret);
+
+       amd64_restore_ecc_error_reporting(pvt);
+
+       if (boot_cpu_data.x86 > 0xf)
+               amd64_teardown(pvt);
+
+       amd64_free_mc_sibling_devices(pvt);
+
+       kfree(pvt_lookup[pvt->mc_node_id]);
+       pvt_lookup[node_id] = NULL;
+
+       return ret;
+}
+
+
+static int __devinit amd64_init_one_instance(struct pci_dev *pdev,
+                                const struct pci_device_id *mc_type)
+{
+       int ret = 0;
+
+       debugf0("(MC node=%d,mc_type='%s')\n",
+               get_mc_node_id_from_pdev(pdev),
+               get_amd_family_name(mc_type->driver_data));
+
+       ret = pci_enable_device(pdev);
+       if (ret < 0)
+               ret = -EIO;
+       else
+               ret = amd64_probe_one_instance(pdev, mc_type->driver_data);
+
+       if (ret < 0)
+               debugf0("ret=%d\n", ret);
+
+       return ret;
+}
+
+static void __devexit amd64_remove_one_instance(struct pci_dev *pdev)
+{
+       struct mem_ctl_info *mci;
+       struct amd64_pvt *pvt;
+
+       /* Remove from EDAC CORE tracking list */
+       mci = edac_mc_del_mc(&pdev->dev);
+       if (!mci)
+               return;
+
+       pvt = mci->pvt_info;
+
+       amd64_restore_ecc_error_reporting(pvt);
+
+       if (boot_cpu_data.x86 > 0xf)
+               amd64_teardown(pvt);
+
+       amd64_free_mc_sibling_devices(pvt);
+
+       kfree(pvt);
+       mci->pvt_info = NULL;
+
+       mci_lookup[pvt->mc_node_id] = NULL;
+
+       /* Free the EDAC CORE resources */
+       edac_mc_free(mci);
+}
+
+/*
+ * This table is part of the interface for loading drivers for PCI devices. The
+ * PCI core identifies what devices are on a system during boot, and then
+ * inquiry this table to see if this driver is for a given device found.
+ */
+static const struct pci_device_id amd64_pci_table[] __devinitdata = {
+       {
+               .vendor         = PCI_VENDOR_ID_AMD,
+               .device         = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .class          = 0,
+               .class_mask     = 0,
+               .driver_data    = K8_CPUS
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_AMD,
+               .device         = PCI_DEVICE_ID_AMD_10H_NB_DRAM,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .class          = 0,
+               .class_mask     = 0,
+               .driver_data    = F10_CPUS
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_AMD,
+               .device         = PCI_DEVICE_ID_AMD_11H_NB_DRAM,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .class          = 0,
+               .class_mask     = 0,
+               .driver_data    = F11_CPUS
+       },
+       {0, }
+};
+MODULE_DEVICE_TABLE(pci, amd64_pci_table);
+
+static struct pci_driver amd64_pci_driver = {
+       .name           = EDAC_MOD_STR,
+       .probe          = amd64_init_one_instance,
+       .remove         = __devexit_p(amd64_remove_one_instance),
+       .id_table       = amd64_pci_table,
+};
+
+static void amd64_setup_pci_device(void)
+{
+       struct mem_ctl_info *mci;
+       struct amd64_pvt *pvt;
+
+       if (amd64_ctl_pci)
+               return;
+
+       mci = mci_lookup[0];
+       if (mci) {
+
+               pvt = mci->pvt_info;
+               amd64_ctl_pci =
+                       edac_pci_create_generic_ctl(&pvt->dram_f2_ctl->dev,
+                                                   EDAC_MOD_STR);
+
+               if (!amd64_ctl_pci) {
+                       pr_warning("%s(): Unable to create PCI control\n",
+                                  __func__);
+
+                       pr_warning("%s(): PCI error report via EDAC not set\n",
+                                  __func__);
+                       }
+       }
+}
+
+static int __init amd64_edac_init(void)
+{
+       int nb, err = -ENODEV;
+
+       edac_printk(KERN_INFO, EDAC_MOD_STR, EDAC_AMD64_VERSION "\n");
+
+       opstate_init();
+
+       if (cache_k8_northbridges() < 0)
+               goto err_exit;
+
+       err = pci_register_driver(&amd64_pci_driver);
+       if (err)
+               return err;
+
+       /*
+        * At this point, the array 'pvt_lookup[]' contains pointers to alloc'd
+        * amd64_pvt structs. These will be used in the 2nd stage init function
+        * to finish initialization of the MC instances.
+        */
+       for (nb = 0; nb < num_k8_northbridges; nb++) {
+               if (!pvt_lookup[nb])
+                       continue;
+
+               err = amd64_init_2nd_stage(pvt_lookup[nb]);
+               if (err)
+                       goto err_exit;
+       }
+
+       amd64_setup_pci_device();
+
+       return 0;
+
+err_exit:
+       debugf0("'finish_setup' stage failed\n");
+       pci_unregister_driver(&amd64_pci_driver);
+
+       return err;
+}
+
+static void __exit amd64_edac_exit(void)
+{
+       if (amd64_ctl_pci)
+               edac_pci_release_generic_ctl(amd64_ctl_pci);
+
+       pci_unregister_driver(&amd64_pci_driver);
+}
+
+module_init(amd64_edac_init);
+module_exit(amd64_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("SoftwareBitMaker: Doug Thompson, "
+               "Dave Peterson, Thayne Harbaugh");
+MODULE_DESCRIPTION("MC support for AMD64 memory controllers - "
+               EDAC_AMD64_VERSION);
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
new file mode 100644 (file)
index 0000000..a159957
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+ * AMD64 class Memory Controller kernel module
+ *
+ * Copyright (c) 2009 SoftwareBitMaker.
+ * Copyright (c) 2009 Advanced Micro Devices, Inc.
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ *     Originally Written by Thayne Harbaugh
+ *
+ *      Changes by Douglas "norsk" Thompson  <dougthompson@xmission.com>:
+ *             - K8 CPU Revision D and greater support
+ *
+ *      Changes by Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>:
+ *             - Module largely rewritten, with new (and hopefully correct)
+ *             code for dealing with node and chip select interleaving,
+ *             various code cleanup, and bug fixes
+ *             - Added support for memory hoisting using DRAM hole address
+ *             register
+ *
+ *     Changes by Douglas "norsk" Thompson <dougthompson@xmission.com>:
+ *             -K8 Rev (1207) revision support added, required Revision
+ *             specific mini-driver code to support Rev F as well as
+ *             prior revisions
+ *
+ *     Changes by Douglas "norsk" Thompson <dougthompson@xmission.com>:
+ *             -Family 10h revision support added. New PCI Device IDs,
+ *             indicating new changes. Actual registers modified
+ *             were slight, less than the Rev E to Rev F transition
+ *             but changing the PCI Device ID was the proper thing to
+ *             do, as it provides for almost automactic family
+ *             detection. The mods to Rev F required more family
+ *             information detection.
+ *
+ *     Changes/Fixes by Borislav Petkov <borislav.petkov@amd.com>:
+ *             - misc fixes and code cleanups
+ *
+ * This module is based on the following documents
+ * (available from http://www.amd.com/):
+ *
+ *     Title:  BIOS and Kernel Developer's Guide for AMD Athlon 64 and AMD
+ *             Opteron Processors
+ *     AMD publication #: 26094
+ *`    Revision: 3.26
+ *
+ *     Title:  BIOS and Kernel Developer's Guide for AMD NPT Family 0Fh
+ *             Processors
+ *     AMD publication #: 32559
+ *     Revision: 3.00
+ *     Issue Date: May 2006
+ *
+ *     Title:  BIOS and Kernel Developer's Guide (BKDG) For AMD Family 10h
+ *             Processors
+ *     AMD publication #: 31116
+ *     Revision: 3.00
+ *     Issue Date: September 07, 2007
+ *
+ * Sections in the first 2 documents are no longer in sync with each other.
+ * The Family 10h BKDG was totally re-written from scratch with a new
+ * presentation model.
+ * Therefore, comments that refer to a Document section might be off.
+ */
+
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include <linux/mmzone.h>
+#include <linux/edac.h>
+#include <asm/msr.h>
+#include "edac_core.h"
+
+#define amd64_printk(level, fmt, arg...) \
+       edac_printk(level, "amd64", fmt, ##arg)
+
+#define amd64_mc_printk(mci, level, fmt, arg...) \
+       edac_mc_chipset_printk(mci, level, "amd64", fmt, ##arg)
+
+/*
+ * Throughout the comments in this code, the following terms are used:
+ *
+ *     SysAddr, DramAddr, and InputAddr
+ *
+ *  These terms come directly from the amd64 documentation
+ * (AMD publication #26094).  They are defined as follows:
+ *
+ *     SysAddr:
+ *         This is a physical address generated by a CPU core or a device
+ *         doing DMA.  If generated by a CPU core, a SysAddr is the result of
+ *         a virtual to physical address translation by the CPU core's address
+ *         translation mechanism (MMU).
+ *
+ *     DramAddr:
+ *         A DramAddr is derived from a SysAddr by subtracting an offset that
+ *         depends on which node the SysAddr maps to and whether the SysAddr
+ *         is within a range affected by memory hoisting.  The DRAM Base
+ *         (section 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers
+ *         determine which node a SysAddr maps to.
+ *
+ *         If the DRAM Hole Address Register (DHAR) is enabled and the SysAddr
+ *         is within the range of addresses specified by this register, then
+ *         a value x from the DHAR is subtracted from the SysAddr to produce a
+ *         DramAddr.  Here, x represents the base address for the node that
+ *         the SysAddr maps to plus an offset due to memory hoisting.  See
+ *         section 3.4.8 and the comments in amd64_get_dram_hole_info() and
+ *         sys_addr_to_dram_addr() below for more information.
+ *
+ *         If the SysAddr is not affected by the DHAR then a value y is
+ *         subtracted from the SysAddr to produce a DramAddr.  Here, y is the
+ *         base address for the node that the SysAddr maps to.  See section
+ *         3.4.4 and the comments in sys_addr_to_dram_addr() below for more
+ *         information.
+ *
+ *     InputAddr:
+ *         A DramAddr is translated to an InputAddr before being passed to the
+ *         memory controller for the node that the DramAddr is associated
+ *         with.  The memory controller then maps the InputAddr to a csrow.
+ *         If node interleaving is not in use, then the InputAddr has the same
+ *         value as the DramAddr.  Otherwise, the InputAddr is produced by
+ *         discarding the bits used for node interleaving from the DramAddr.
+ *         See section 3.4.4 for more information.
+ *
+ *         The memory controller for a given node uses its DRAM CS Base and
+ *         DRAM CS Mask registers to map an InputAddr to a csrow.  See
+ *         sections 3.5.4 and 3.5.5 for more information.
+ */
+
+#define EDAC_AMD64_VERSION             " Ver: 3.2.0 " __DATE__
+#define EDAC_MOD_STR                   "amd64_edac"
+
+/* Extended Model from CPUID, for CPU Revision numbers */
+#define OPTERON_CPU_LE_REV_C           0
+#define OPTERON_CPU_REV_D              1
+#define OPTERON_CPU_REV_E              2
+
+/* NPT processors have the following Extended Models */
+#define OPTERON_CPU_REV_F              4
+#define OPTERON_CPU_REV_FA             5
+
+/* Hardware limit on ChipSelect rows per MC and processors per system */
+#define CHIPSELECT_COUNT               8
+#define DRAM_REG_COUNT                 8
+
+
+/*
+ * PCI-defined configuration space registers
+ */
+
+
+/*
+ * Function 1 - Address Map
+ */
+#define K8_DRAM_BASE_LOW               0x40
+#define K8_DRAM_LIMIT_LOW              0x44
+#define K8_DHAR                                0xf0
+
+#define DHAR_VALID                     BIT(0)
+#define F10_DRAM_MEM_HOIST_VALID       BIT(1)
+
+#define DHAR_BASE_MASK                 0xff000000
+#define dhar_base(dhar)                        (dhar & DHAR_BASE_MASK)
+
+#define K8_DHAR_OFFSET_MASK            0x0000ff00
+#define k8_dhar_offset(dhar)           ((dhar & K8_DHAR_OFFSET_MASK) << 16)
+
+#define F10_DHAR_OFFSET_MASK           0x0000ff80
+                                       /* NOTE: Extra mask bit vs K8 */
+#define f10_dhar_offset(dhar)          ((dhar & F10_DHAR_OFFSET_MASK) << 16)
+
+
+/* F10 High BASE/LIMIT registers */
+#define F10_DRAM_BASE_HIGH             0x140
+#define F10_DRAM_LIMIT_HIGH            0x144
+
+
+/*
+ * Function 2 - DRAM controller
+ */
+#define K8_DCSB0                       0x40
+#define F10_DCSB1                      0x140
+
+#define K8_DCSB_CS_ENABLE              BIT(0)
+#define K8_DCSB_NPT_SPARE              BIT(1)
+#define K8_DCSB_NPT_TESTFAIL           BIT(2)
+
+/*
+ * REV E: select [31:21] and [15:9] from DCSB and the shift amount to form
+ * the address
+ */
+#define REV_E_DCSB_BASE_BITS           (0xFFE0FE00ULL)
+#define REV_E_DCS_SHIFT                        4
+#define REV_E_DCSM_COUNT               8
+
+#define REV_F_F1Xh_DCSB_BASE_BITS      (0x1FF83FE0ULL)
+#define REV_F_F1Xh_DCS_SHIFT           8
+
+/*
+ * REV F and later: selects [28:19] and [13:5] from DCSB and the shift amount
+ * to form the address
+ */
+#define REV_F_DCSB_BASE_BITS           (0x1FF83FE0ULL)
+#define REV_F_DCS_SHIFT                        8
+#define REV_F_DCSM_COUNT               4
+#define F10_DCSM_COUNT                 4
+#define F11_DCSM_COUNT                 2
+
+/* DRAM CS Mask Registers */
+#define K8_DCSM0                       0x60
+#define F10_DCSM1                      0x160
+
+/* REV E: select [29:21] and [15:9] from DCSM */
+#define REV_E_DCSM_MASK_BITS           0x3FE0FE00
+
+/* unused bits [24:20] and [12:0] */
+#define REV_E_DCS_NOTUSED_BITS         0x01F01FFF
+
+/* REV F and later: select [28:19] and [13:5] from DCSM */
+#define REV_F_F1Xh_DCSM_MASK_BITS      0x1FF83FE0
+
+/* unused bits [26:22] and [12:0] */
+#define REV_F_F1Xh_DCS_NOTUSED_BITS    0x07C01FFF
+
+#define DBAM0                          0x80
+#define DBAM1                          0x180
+
+/* Extract the DIMM 'type' on the i'th DIMM from the DBAM reg value passed */
+#define DBAM_DIMM(i, reg)              ((((reg) >> (4*i))) & 0xF)
+
+#define DBAM_MAX_VALUE                 11
+
+
+#define F10_DCLR_0                     0x90
+#define F10_DCLR_1                     0x190
+#define REVE_WIDTH_128                 BIT(16)
+#define F10_WIDTH_128                  BIT(11)
+
+
+#define F10_DCHR_0                     0x94
+#define F10_DCHR_1                     0x194
+
+#define F10_DCHR_FOUR_RANK_DIMM                BIT(18)
+#define F10_DCHR_Ddr3Mode              BIT(8)
+#define F10_DCHR_MblMode               BIT(6)
+
+
+#define F10_DCTL_SEL_LOW               0x110
+
+#define dct_sel_baseaddr(pvt)    \
+       ((pvt->dram_ctl_select_low) & 0xFFFFF800)
+
+#define dct_sel_interleave_addr(pvt)    \
+       (((pvt->dram_ctl_select_low) >> 6) & 0x3)
+
+enum {
+       F10_DCTL_SEL_LOW_DctSelHiRngEn  = BIT(0),
+       F10_DCTL_SEL_LOW_DctSelIntLvEn  = BIT(2),
+       F10_DCTL_SEL_LOW_DctGangEn      = BIT(4),
+       F10_DCTL_SEL_LOW_DctDatIntLv    = BIT(5),
+       F10_DCTL_SEL_LOW_DramEnable     = BIT(8),
+       F10_DCTL_SEL_LOW_MemCleared     = BIT(10),
+};
+
+#define    dct_high_range_enabled(pvt)    \
+       (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctSelHiRngEn)
+
+#define dct_interleave_enabled(pvt)       \
+       (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctSelIntLvEn)
+
+#define dct_ganging_enabled(pvt)        \
+       (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctGangEn)
+
+#define dct_data_intlv_enabled(pvt)    \
+       (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctDatIntLv)
+
+#define dct_dram_enabled(pvt)    \
+       (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DramEnable)
+
+#define dct_memory_cleared(pvt)    \
+       (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_MemCleared)
+
+
+#define F10_DCTL_SEL_HIGH              0x114
+
+
+/*
+ * Function 3 - Misc Control
+ */
+#define K8_NBCTL                       0x40
+
+/* Correctable ECC error reporting enable */
+#define K8_NBCTL_CECCEn                        BIT(0)
+
+/* UnCorrectable ECC error reporting enable */
+#define K8_NBCTL_UECCEn                        BIT(1)
+
+#define K8_NBCFG                       0x44
+#define K8_NBCFG_CHIPKILL              BIT(23)
+#define K8_NBCFG_ECC_ENABLE            BIT(22)
+
+#define K8_NBSL                                0x48
+
+
+#define EXTRACT_HIGH_SYNDROME(x)       (((x) >> 24) & 0xff)
+#define EXTRACT_EXT_ERROR_CODE(x)      (((x) >> 16) & 0x1f)
+
+/* Family F10h: Normalized Extended Error Codes */
+#define F10_NBSL_EXT_ERR_RES           0x0
+#define F10_NBSL_EXT_ERR_CRC           0x1
+#define F10_NBSL_EXT_ERR_SYNC          0x2
+#define F10_NBSL_EXT_ERR_MST           0x3
+#define F10_NBSL_EXT_ERR_TGT           0x4
+#define F10_NBSL_EXT_ERR_GART          0x5
+#define F10_NBSL_EXT_ERR_RMW           0x6
+#define F10_NBSL_EXT_ERR_WDT           0x7
+#define F10_NBSL_EXT_ERR_ECC           0x8
+#define F10_NBSL_EXT_ERR_DEV           0x9
+#define F10_NBSL_EXT_ERR_LINK_DATA     0xA
+
+/* Next two are overloaded values */
+#define F10_NBSL_EXT_ERR_LINK_PROTO    0xB
+#define F10_NBSL_EXT_ERR_L3_PROTO      0xB
+
+#define F10_NBSL_EXT_ERR_NB_ARRAY      0xC
+#define F10_NBSL_EXT_ERR_DRAM_PARITY   0xD
+#define F10_NBSL_EXT_ERR_LINK_RETRY    0xE
+
+/* Next two are overloaded values */
+#define F10_NBSL_EXT_ERR_GART_WALK     0xF
+#define F10_NBSL_EXT_ERR_DEV_WALK      0xF
+
+/* 0x10 to 0x1B: Reserved */
+#define F10_NBSL_EXT_ERR_L3_DATA       0x1C
+#define F10_NBSL_EXT_ERR_L3_TAG                0x1D
+#define F10_NBSL_EXT_ERR_L3_LRU                0x1E
+
+/* K8: Normalized Extended Error Codes */
+#define K8_NBSL_EXT_ERR_ECC            0x0
+#define K8_NBSL_EXT_ERR_CRC            0x1
+#define K8_NBSL_EXT_ERR_SYNC           0x2
+#define K8_NBSL_EXT_ERR_MST            0x3
+#define K8_NBSL_EXT_ERR_TGT            0x4
+#define K8_NBSL_EXT_ERR_GART           0x5
+#define K8_NBSL_EXT_ERR_RMW            0x6
+#define K8_NBSL_EXT_ERR_WDT            0x7
+#define K8_NBSL_EXT_ERR_CHIPKILL_ECC   0x8
+#define K8_NBSL_EXT_ERR_DRAM_PARITY    0xD
+
+#define EXTRACT_ERROR_CODE(x)          ((x) & 0xffff)
+#define        TEST_TLB_ERROR(x)               (((x) & 0xFFF0) == 0x0010)
+#define        TEST_MEM_ERROR(x)               (((x) & 0xFF00) == 0x0100)
+#define        TEST_BUS_ERROR(x)               (((x) & 0xF800) == 0x0800)
+#define        EXTRACT_TT_CODE(x)              (((x) >> 2) & 0x3)
+#define        EXTRACT_II_CODE(x)              (((x) >> 2) & 0x3)
+#define        EXTRACT_LL_CODE(x)              (((x) >> 0) & 0x3)
+#define        EXTRACT_RRRR_CODE(x)            (((x) >> 4) & 0xf)
+#define        EXTRACT_TO_CODE(x)              (((x) >> 8) & 0x1)
+#define        EXTRACT_PP_CODE(x)              (((x) >> 9) & 0x3)
+
+/*
+ * The following are for BUS type errors AFTER values have been normalized by
+ * shifting right
+ */
+#define K8_NBSL_PP_SRC                 0x0
+#define K8_NBSL_PP_RES                 0x1
+#define K8_NBSL_PP_OBS                 0x2
+#define K8_NBSL_PP_GENERIC             0x3
+
+
+#define K8_NBSH                                0x4C
+
+#define K8_NBSH_VALID_BIT              BIT(31)
+#define K8_NBSH_OVERFLOW               BIT(30)
+#define K8_NBSH_UNCORRECTED_ERR                BIT(29)
+#define K8_NBSH_ERR_ENABLE             BIT(28)
+#define K8_NBSH_MISC_ERR_VALID         BIT(27)
+#define K8_NBSH_VALID_ERROR_ADDR       BIT(26)
+#define K8_NBSH_PCC                    BIT(25)
+#define K8_NBSH_CECC                   BIT(14)
+#define K8_NBSH_UECC                   BIT(13)
+#define K8_NBSH_ERR_SCRUBER            BIT(8)
+#define K8_NBSH_CORE3                  BIT(3)
+#define K8_NBSH_CORE2                  BIT(2)
+#define K8_NBSH_CORE1                  BIT(1)
+#define K8_NBSH_CORE0                  BIT(0)
+
+#define EXTRACT_LDT_LINK(x)            (((x) >> 4) & 0x7)
+#define EXTRACT_ERR_CPU_MAP(x)         ((x) & 0xF)
+#define EXTRACT_LOW_SYNDROME(x)                (((x) >> 15) & 0xff)
+
+
+#define K8_NBEAL                       0x50
+#define K8_NBEAH                       0x54
+#define K8_SCRCTRL                     0x58
+
+#define F10_NB_CFG_LOW                 0x88
+#define        F10_NB_CFG_LOW_ENABLE_EXT_CFG   BIT(14)
+
+#define F10_NB_CFG_HIGH                        0x8C
+
+#define F10_ONLINE_SPARE               0xB0
+#define F10_ONLINE_SPARE_SWAPDONE0(x)  ((x) & BIT(1))
+#define F10_ONLINE_SPARE_SWAPDONE1(x)  ((x) & BIT(3))
+#define F10_ONLINE_SPARE_BADDRAM_CS0(x) (((x) >> 4) & 0x00000007)
+#define F10_ONLINE_SPARE_BADDRAM_CS1(x) (((x) >> 8) & 0x00000007)
+
+#define F10_NB_ARRAY_ADDR              0xB8
+
+#define F10_NB_ARRAY_DRAM_ECC          0x80000000
+
+/* Bits [2:1] are used to select 16-byte section within a 64-byte cacheline  */
+#define SET_NB_ARRAY_ADDRESS(section)  (((section) & 0x3) << 1)
+
+#define F10_NB_ARRAY_DATA              0xBC
+
+#define SET_NB_DRAM_INJECTION_WRITE(word, bits)  \
+                                       (BIT(((word) & 0xF) + 20) | \
+                                       BIT(17) |  \
+                                       ((bits) & 0xF))
+
+#define SET_NB_DRAM_INJECTION_READ(word, bits)  \
+                                       (BIT(((word) & 0xF) + 20) | \
+                                       BIT(16) |  \
+                                       ((bits) & 0xF))
+
+#define K8_NBCAP                       0xE8
+#define K8_NBCAP_CORES                 (BIT(12)|BIT(13))
+#define K8_NBCAP_CHIPKILL              BIT(4)
+#define K8_NBCAP_SECDED                        BIT(3)
+#define K8_NBCAP_8_NODE                        BIT(2)
+#define K8_NBCAP_DUAL_NODE             BIT(1)
+#define K8_NBCAP_DCT_DUAL              BIT(0)
+
+/*
+ * MSR Regs
+ */
+#define K8_MSR_MCGCTL                  0x017b
+#define K8_MSR_MCGCTL_NBE              BIT(4)
+
+#define K8_MSR_MC4CTL                  0x0410
+#define K8_MSR_MC4STAT                 0x0411
+#define K8_MSR_MC4ADDR                 0x0412
+
+/* AMD sets the first MC device at device ID 0x18. */
+static inline int get_mc_node_id_from_pdev(struct pci_dev *pdev)
+{
+       return PCI_SLOT(pdev->devfn) - 0x18;
+}
+
+enum amd64_chipset_families {
+       K8_CPUS = 0,
+       F10_CPUS,
+       F11_CPUS,
+};
+
+/*
+ * Structure to hold:
+ *
+ * 1) dynamically read status and error address HW registers
+ * 2) sysfs entered values
+ * 3) MCE values
+ *
+ * Depends on entry into the modules
+ */
+struct amd64_error_info_regs {
+       u32 nbcfg;
+       u32 nbsh;
+       u32 nbsl;
+       u32 nbeah;
+       u32 nbeal;
+};
+
+/* Error injection control structure */
+struct error_injection {
+       u32     section;
+       u32     word;
+       u32     bit_map;
+};
+
+struct amd64_pvt {
+       /* pci_device handles which we utilize */
+       struct pci_dev *addr_f1_ctl;
+       struct pci_dev *dram_f2_ctl;
+       struct pci_dev *misc_f3_ctl;
+
+       int mc_node_id;         /* MC index of this MC node */
+       int ext_model;          /* extended model value of this node */
+
+       struct low_ops *ops;    /* pointer to per PCI Device ID func table */
+
+       int channel_count;
+
+       /* Raw registers */
+       u32 dclr0;              /* DRAM Configuration Low DCT0 reg */
+       u32 dclr1;              /* DRAM Configuration Low DCT1 reg */
+       u32 dchr0;              /* DRAM Configuration High DCT0 reg */
+       u32 dchr1;              /* DRAM Configuration High DCT1 reg */
+       u32 nbcap;              /* North Bridge Capabilities */
+       u32 nbcfg;              /* F10 North Bridge Configuration */
+       u32 ext_nbcfg;          /* Extended F10 North Bridge Configuration */
+       u32 dhar;               /* DRAM Hoist reg */
+       u32 dbam0;              /* DRAM Base Address Mapping reg for DCT0 */
+       u32 dbam1;              /* DRAM Base Address Mapping reg for DCT1 */
+
+       /* DRAM CS Base Address Registers F2x[1,0][5C:40] */
+       u32 dcsb0[CHIPSELECT_COUNT];
+       u32 dcsb1[CHIPSELECT_COUNT];
+
+       /* DRAM CS Mask Registers F2x[1,0][6C:60] */
+       u32 dcsm0[CHIPSELECT_COUNT];
+       u32 dcsm1[CHIPSELECT_COUNT];
+
+       /*
+        * Decoded parts of DRAM BASE and LIMIT Registers
+        * F1x[78,70,68,60,58,50,48,40]
+        */
+       u64 dram_base[DRAM_REG_COUNT];
+       u64 dram_limit[DRAM_REG_COUNT];
+       u8  dram_IntlvSel[DRAM_REG_COUNT];
+       u8  dram_IntlvEn[DRAM_REG_COUNT];
+       u8  dram_DstNode[DRAM_REG_COUNT];
+       u8  dram_rw_en[DRAM_REG_COUNT];
+
+       /*
+        * The following fields are set at (load) run time, after CPU revision
+        * has been determined, since the dct_base and dct_mask registers vary
+        * based on revision
+        */
+       u32 dcsb_base;          /* DCSB base bits */
+       u32 dcsm_mask;          /* DCSM mask bits */
+       u32 num_dcsm;           /* Number of DCSM registers */
+       u32 dcs_mask_notused;   /* DCSM notused mask bits */
+       u32 dcs_shift;          /* DCSB and DCSM shift value */
+
+       u64 top_mem;            /* top of memory below 4GB */
+       u64 top_mem2;           /* top of memory above 4GB */
+
+       u32 dram_ctl_select_low;        /* DRAM Controller Select Low Reg */
+       u32 dram_ctl_select_high;       /* DRAM Controller Select High Reg */
+       u32 online_spare;               /* On-Line spare Reg */
+
+       /* temp storage for when input is received from sysfs */
+       struct amd64_error_info_regs ctl_error_info;
+
+       /* place to store error injection parameters prior to issue */
+       struct error_injection injection;
+
+       /* Save old hw registers' values before we modified them */
+       u32 nbctl_mcgctl_saved;         /* When true, following 2 are valid */
+       u32 old_nbctl;
+       unsigned long old_mcgctl;       /* per core on this node */
+
+       /* MC Type Index value: socket F vs Family 10h */
+       u32 mc_type_index;
+
+       /* misc settings */
+       struct flags {
+               unsigned long cf8_extcfg:1;
+       } flags;
+};
+
+struct scrubrate {
+       u32 scrubval;           /* bit pattern for scrub rate */
+       u32 bandwidth;          /* bandwidth consumed (bytes/sec) */
+};
+
+extern struct scrubrate scrubrates[23];
+extern u32 revf_quad_ddr2_shift[16];
+extern const char *tt_msgs[4];
+extern const char *ll_msgs[4];
+extern const char *rrrr_msgs[16];
+extern const char *to_msgs[2];
+extern const char *pp_msgs[4];
+extern const char *ii_msgs[4];
+extern const char *ext_msgs[32];
+extern const char *htlink_msgs[8];
+
+#ifdef CONFIG_EDAC_DEBUG
+#define NUM_DBG_ATTRS 9
+#else
+#define NUM_DBG_ATTRS 0
+#endif
+
+#ifdef CONFIG_EDAC_AMD64_ERROR_INJECTION
+#define NUM_INJ_ATTRS 5
+#else
+#define NUM_INJ_ATTRS 0
+#endif
+
+extern struct mcidev_sysfs_attribute amd64_dbg_attrs[NUM_DBG_ATTRS],
+                                    amd64_inj_attrs[NUM_INJ_ATTRS];
+
+/*
+ * Each of the PCI Device IDs types have their own set of hardware accessor
+ * functions and per device encoding/decoding logic.
+ */
+struct low_ops {
+       int (*probe_valid_hardware)(struct amd64_pvt *pvt);
+       int (*early_channel_count)(struct amd64_pvt *pvt);
+
+       u64 (*get_error_address)(struct mem_ctl_info *mci,
+                       struct amd64_error_info_regs *info);
+       void (*read_dram_base_limit)(struct amd64_pvt *pvt, int dram);
+       void (*read_dram_ctl_register)(struct amd64_pvt *pvt);
+       void (*map_sysaddr_to_csrow)(struct mem_ctl_info *mci,
+                                       struct amd64_error_info_regs *info,
+                                       u64 SystemAddr);
+       int (*dbam_map_to_pages)(struct amd64_pvt *pvt, int dram_map);
+};
+
+struct amd64_family_type {
+       const char *ctl_name;
+       u16 addr_f1_ctl;
+       u16 misc_f3_ctl;
+       struct low_ops ops;
+};
+
+static struct amd64_family_type amd64_family_types[];
+
+static inline const char *get_amd_family_name(int index)
+{
+       return amd64_family_types[index].ctl_name;
+}
+
+static inline struct low_ops *family_ops(int index)
+{
+       return &amd64_family_types[index].ops;
+}
+
+/*
+ * For future CPU versions, verify the following as new 'slow' rates appear and
+ * modify the necessary skip values for the supported CPU.
+ */
+#define K8_MIN_SCRUB_RATE_BITS 0x0
+#define F10_MIN_SCRUB_RATE_BITS        0x5
+#define F11_MIN_SCRUB_RATE_BITS        0x6
+
+int amd64_process_error_info(struct mem_ctl_info *mci,
+                            struct amd64_error_info_regs *info,
+                            int handle_errors);
+int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
+                            u64 *hole_offset, u64 *hole_size);
diff --git a/drivers/edac/amd64_edac_dbg.c b/drivers/edac/amd64_edac_dbg.c
new file mode 100644 (file)
index 0000000..0a41b24
--- /dev/null
@@ -0,0 +1,255 @@
+#include "amd64_edac.h"
+
+/*
+ * accept a hex value and store it into the virtual error register file, field:
+ * nbeal and nbeah. Assume virtual error values have already been set for: NBSL,
+ * NBSH and NBCFG. Then proceed to map the error values to a MC, CSROW and
+ * CHANNEL
+ */
+static ssize_t amd64_nbea_store(struct mem_ctl_info *mci, const char *data,
+                               size_t count)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       unsigned long long value;
+       int ret = 0;
+
+       ret = strict_strtoull(data, 16, &value);
+       if (ret != -EINVAL) {
+               debugf0("received NBEA= 0x%llx\n", value);
+
+               /* place the value into the virtual error packet */
+               pvt->ctl_error_info.nbeal = (u32) value;
+               value >>= 32;
+               pvt->ctl_error_info.nbeah = (u32) value;
+
+               /* Process the Mapping request */
+               /* TODO: Add race prevention */
+               amd64_process_error_info(mci, &pvt->ctl_error_info, 1);
+
+               return count;
+       }
+       return ret;
+}
+
+/* display back what the last NBEA (MCA NB Address (MC4_ADDR)) was written */
+static ssize_t amd64_nbea_show(struct mem_ctl_info *mci, char *data)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       u64 value;
+
+       value = pvt->ctl_error_info.nbeah;
+       value <<= 32;
+       value |= pvt->ctl_error_info.nbeal;
+
+       return sprintf(data, "%llx\n", value);
+}
+
+/* store the NBSL (MCA NB Status Low (MC4_STATUS)) value user desires */
+static ssize_t amd64_nbsl_store(struct mem_ctl_info *mci, const char *data,
+                               size_t count)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       unsigned long value;
+       int ret = 0;
+
+       ret = strict_strtoul(data, 16, &value);
+       if (ret != -EINVAL) {
+               debugf0("received NBSL= 0x%lx\n", value);
+
+               pvt->ctl_error_info.nbsl = (u32) value;
+
+               return count;
+       }
+       return ret;
+}
+
+/* display back what the last NBSL value written */
+static ssize_t amd64_nbsl_show(struct mem_ctl_info *mci, char *data)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       u32 value;
+
+       value = pvt->ctl_error_info.nbsl;
+
+       return sprintf(data, "%x\n", value);
+}
+
+/* store the NBSH (MCA NB Status High) value user desires */
+static ssize_t amd64_nbsh_store(struct mem_ctl_info *mci, const char *data,
+                               size_t count)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       unsigned long value;
+       int ret = 0;
+
+       ret = strict_strtoul(data, 16, &value);
+       if (ret != -EINVAL) {
+               debugf0("received NBSH= 0x%lx\n", value);
+
+               pvt->ctl_error_info.nbsh = (u32) value;
+
+               return count;
+       }
+       return ret;
+}
+
+/* display back what the last NBSH value written */
+static ssize_t amd64_nbsh_show(struct mem_ctl_info *mci, char *data)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       u32 value;
+
+       value = pvt->ctl_error_info.nbsh;
+
+       return sprintf(data, "%x\n", value);
+}
+
+/* accept and store the NBCFG (MCA NB Configuration) value user desires */
+static ssize_t amd64_nbcfg_store(struct mem_ctl_info *mci,
+                                       const char *data, size_t count)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       unsigned long value;
+       int ret = 0;
+
+       ret = strict_strtoul(data, 16, &value);
+       if (ret != -EINVAL) {
+               debugf0("received NBCFG= 0x%lx\n", value);
+
+               pvt->ctl_error_info.nbcfg = (u32) value;
+
+               return count;
+       }
+       return ret;
+}
+
+/* various show routines for the controls of a MCI */
+static ssize_t amd64_nbcfg_show(struct mem_ctl_info *mci, char *data)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+
+       return sprintf(data, "%x\n", pvt->ctl_error_info.nbcfg);
+}
+
+
+static ssize_t amd64_dhar_show(struct mem_ctl_info *mci, char *data)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+
+       return sprintf(data, "%x\n", pvt->dhar);
+}
+
+
+static ssize_t amd64_dbam_show(struct mem_ctl_info *mci, char *data)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+
+       return sprintf(data, "%x\n", pvt->dbam0);
+}
+
+
+static ssize_t amd64_topmem_show(struct mem_ctl_info *mci, char *data)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+
+       return sprintf(data, "%llx\n", pvt->top_mem);
+}
+
+
+static ssize_t amd64_topmem2_show(struct mem_ctl_info *mci, char *data)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+
+       return sprintf(data, "%llx\n", pvt->top_mem2);
+}
+
+static ssize_t amd64_hole_show(struct mem_ctl_info *mci, char *data)
+{
+       u64 hole_base = 0;
+       u64 hole_offset = 0;
+       u64 hole_size = 0;
+
+       amd64_get_dram_hole_info(mci, &hole_base, &hole_offset, &hole_size);
+
+       return sprintf(data, "%llx %llx %llx\n", hole_base, hole_offset,
+                                                hole_size);
+}
+
+/*
+ * update NUM_DBG_ATTRS in case you add new members
+ */
+struct mcidev_sysfs_attribute amd64_dbg_attrs[] = {
+
+       {
+               .attr = {
+                       .name = "nbea_ctl",
+                       .mode = (S_IRUGO | S_IWUSR)
+               },
+               .show = amd64_nbea_show,
+               .store = amd64_nbea_store,
+       },
+       {
+               .attr = {
+                       .name = "nbsl_ctl",
+                       .mode = (S_IRUGO | S_IWUSR)
+               },
+               .show = amd64_nbsl_show,
+               .store = amd64_nbsl_store,
+       },
+       {
+               .attr = {
+                       .name = "nbsh_ctl",
+                       .mode = (S_IRUGO | S_IWUSR)
+               },
+               .show = amd64_nbsh_show,
+               .store = amd64_nbsh_store,
+       },
+       {
+               .attr = {
+                       .name = "nbcfg_ctl",
+                       .mode = (S_IRUGO | S_IWUSR)
+               },
+               .show = amd64_nbcfg_show,
+               .store = amd64_nbcfg_store,
+       },
+       {
+               .attr = {
+                       .name = "dhar",
+                       .mode = (S_IRUGO)
+               },
+               .show = amd64_dhar_show,
+               .store = NULL,
+       },
+       {
+               .attr = {
+                       .name = "dbam",
+                       .mode = (S_IRUGO)
+               },
+               .show = amd64_dbam_show,
+               .store = NULL,
+       },
+       {
+               .attr = {
+                       .name = "topmem",
+                       .mode = (S_IRUGO)
+               },
+               .show = amd64_topmem_show,
+               .store = NULL,
+       },
+       {
+               .attr = {
+                       .name = "topmem2",
+                       .mode = (S_IRUGO)
+               },
+               .show = amd64_topmem2_show,
+               .store = NULL,
+       },
+       {
+               .attr = {
+                       .name = "dram_hole",
+                       .mode = (S_IRUGO)
+               },
+               .show = amd64_hole_show,
+               .store = NULL,
+       },
+};
diff --git a/drivers/edac/amd64_edac_err_types.c b/drivers/edac/amd64_edac_err_types.c
new file mode 100644 (file)
index 0000000..f212ff1
--- /dev/null
@@ -0,0 +1,161 @@
+#include "amd64_edac.h"
+
+/*
+ * See F2x80 for K8 and F2x[1,0]80 for Fam10 and later. The table below is only
+ * for DDR2 DRAM mapping.
+ */
+u32 revf_quad_ddr2_shift[] = {
+       0,      /* 0000b NULL DIMM (128mb) */
+       28,     /* 0001b 256mb */
+       29,     /* 0010b 512mb */
+       29,     /* 0011b 512mb */
+       29,     /* 0100b 512mb */
+       30,     /* 0101b 1gb */
+       30,     /* 0110b 1gb */
+       31,     /* 0111b 2gb */
+       31,     /* 1000b 2gb */
+       32,     /* 1001b 4gb */
+       32,     /* 1010b 4gb */
+       33,     /* 1011b 8gb */
+       0,      /* 1100b future */
+       0,      /* 1101b future */
+       0,      /* 1110b future */
+       0       /* 1111b future */
+};
+
+/*
+ * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing
+ * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching-
+ * or higher value'.
+ *
+ *FIXME: Produce a better mapping/linearisation.
+ */
+
+struct scrubrate scrubrates[] = {
+       { 0x01, 1600000000UL},
+       { 0x02, 800000000UL},
+       { 0x03, 400000000UL},
+       { 0x04, 200000000UL},
+       { 0x05, 100000000UL},
+       { 0x06, 50000000UL},
+       { 0x07, 25000000UL},
+       { 0x08, 12284069UL},
+       { 0x09, 6274509UL},
+       { 0x0A, 3121951UL},
+       { 0x0B, 1560975UL},
+       { 0x0C, 781440UL},
+       { 0x0D, 390720UL},
+       { 0x0E, 195300UL},
+       { 0x0F, 97650UL},
+       { 0x10, 48854UL},
+       { 0x11, 24427UL},
+       { 0x12, 12213UL},
+       { 0x13, 6101UL},
+       { 0x14, 3051UL},
+       { 0x15, 1523UL},
+       { 0x16, 761UL},
+       { 0x00, 0UL},        /* scrubbing off */
+};
+
+/*
+ * string representation for the different MCA reported error types, see F3x48
+ * or MSR0000_0411.
+ */
+const char *tt_msgs[] = {        /* transaction type */
+       "instruction",
+       "data",
+       "generic",
+       "reserved"
+};
+
+const char *ll_msgs[] = {      /* cache level */
+       "L0",
+       "L1",
+       "L2",
+       "L3/generic"
+};
+
+const char *rrrr_msgs[] = {
+       "generic",
+       "generic read",
+       "generic write",
+       "data read",
+       "data write",
+       "inst fetch",
+       "prefetch",
+       "evict",
+       "snoop",
+       "reserved RRRR= 9",
+       "reserved RRRR= 10",
+       "reserved RRRR= 11",
+       "reserved RRRR= 12",
+       "reserved RRRR= 13",
+       "reserved RRRR= 14",
+       "reserved RRRR= 15"
+};
+
+const char *pp_msgs[] = {      /* participating processor */
+       "local node originated (SRC)",
+       "local node responded to request (RES)",
+       "local node observed as 3rd party (OBS)",
+       "generic"
+};
+
+const char *to_msgs[] = {
+       "no timeout",
+       "timed out"
+};
+
+const char *ii_msgs[] = {      /* memory or i/o */
+       "mem access",
+       "reserved",
+       "i/o access",
+       "generic"
+};
+
+/* Map the 5 bits of Extended Error code to the string table. */
+const char *ext_msgs[] = {     /* extended error */
+       "K8 ECC error/F10 reserved",    /* 0_0000b */
+       "CRC error",                    /* 0_0001b */
+       "sync error",                   /* 0_0010b */
+       "mst abort",                    /* 0_0011b */
+       "tgt abort",                    /* 0_0100b */
+       "GART error",                   /* 0_0101b */
+       "RMW error",                    /* 0_0110b */
+       "Wdog timer error",             /* 0_0111b */
+       "F10-ECC/K8-Chipkill error",    /* 0_1000b */
+       "DEV Error",                    /* 0_1001b */
+       "Link Data error",              /* 0_1010b */
+       "Link or L3 Protocol error",    /* 0_1011b */
+       "NB Array error",               /* 0_1100b */
+       "DRAM Parity error",            /* 0_1101b */
+       "Link Retry/GART Table Walk/DEV Table Walk error", /* 0_1110b */
+       "Res 0x0ff error",              /* 0_1111b */
+       "Res 0x100 error",              /* 1_0000b */
+       "Res 0x101 error",              /* 1_0001b */
+       "Res 0x102 error",              /* 1_0010b */
+       "Res 0x103 error",              /* 1_0011b */
+       "Res 0x104 error",              /* 1_0100b */
+       "Res 0x105 error",              /* 1_0101b */
+       "Res 0x106 error",              /* 1_0110b */
+       "Res 0x107 error",              /* 1_0111b */
+       "Res 0x108 error",              /* 1_1000b */
+       "Res 0x109 error",              /* 1_1001b */
+       "Res 0x10A error",              /* 1_1010b */
+       "Res 0x10B error",              /* 1_1011b */
+       "L3 Cache Data error",          /* 1_1100b */
+       "L3 CacheTag error",            /* 1_1101b */
+       "L3 Cache LRU error",           /* 1_1110b */
+       "Res 0x1FF error"               /* 1_1111b */
+};
+
+const char *htlink_msgs[] = {
+       "none",
+       "1",
+       "2",
+       "1 2",
+       "3",
+       "1 3",
+       "2 3",
+       "1 2 3"
+};
diff --git a/drivers/edac/amd64_edac_inj.c b/drivers/edac/amd64_edac_inj.c
new file mode 100644 (file)
index 0000000..d3675b7
--- /dev/null
@@ -0,0 +1,185 @@
+#include "amd64_edac.h"
+
+/*
+ * store error injection section value which refers to one of 4 16-byte sections
+ * within a 64-byte cacheline
+ *
+ * range: 0..3
+ */
+static ssize_t amd64_inject_section_store(struct mem_ctl_info *mci,
+                                         const char *data, size_t count)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       unsigned long value;
+       int ret = 0;
+
+       ret = strict_strtoul(data, 10, &value);
+       if (ret != -EINVAL) {
+               pvt->injection.section = (u32) value;
+               return count;
+       }
+       return ret;
+}
+
+/*
+ * store error injection word value which refers to one of 9 16-bit word of the
+ * 16-byte (128-bit + ECC bits) section
+ *
+ * range: 0..8
+ */
+static ssize_t amd64_inject_word_store(struct mem_ctl_info *mci,
+                                       const char *data, size_t count)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       unsigned long value;
+       int ret = 0;
+
+       ret = strict_strtoul(data, 10, &value);
+       if (ret != -EINVAL) {
+
+               value = (value <= 8) ? value : 0;
+               pvt->injection.word = (u32) value;
+
+               return count;
+       }
+       return ret;
+}
+
+/*
+ * store 16 bit error injection vector which enables injecting errors to the
+ * corresponding bit within the error injection word above. When used during a
+ * DRAM ECC read, it holds the contents of the of the DRAM ECC bits.
+ */
+static ssize_t amd64_inject_ecc_vector_store(struct mem_ctl_info *mci,
+                                            const char *data, size_t count)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       unsigned long value;
+       int ret = 0;
+
+       ret = strict_strtoul(data, 16, &value);
+       if (ret != -EINVAL) {
+
+               pvt->injection.bit_map = (u32) value & 0xFFFF;
+
+               return count;
+       }
+       return ret;
+}
+
+/*
+ * Do a DRAM ECC read. Assemble staged values in the pvt area, format into
+ * fields needed by the injection registers and read the NB Array Data Port.
+ */
+static ssize_t amd64_inject_read_store(struct mem_ctl_info *mci,
+                                       const char *data, size_t count)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       unsigned long value;
+       u32 section, word_bits;
+       int ret = 0;
+
+       ret = strict_strtoul(data, 10, &value);
+       if (ret != -EINVAL) {
+
+               /* Form value to choose 16-byte section of cacheline */
+               section = F10_NB_ARRAY_DRAM_ECC |
+                               SET_NB_ARRAY_ADDRESS(pvt->injection.section);
+               pci_write_config_dword(pvt->misc_f3_ctl,
+                                       F10_NB_ARRAY_ADDR, section);
+
+               word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection.word,
+                                               pvt->injection.bit_map);
+
+               /* Issue 'word' and 'bit' along with the READ request */
+               pci_write_config_dword(pvt->misc_f3_ctl,
+                                       F10_NB_ARRAY_DATA, word_bits);
+
+               debugf0("section=0x%x word_bits=0x%x\n", section, word_bits);
+
+               return count;
+       }
+       return ret;
+}
+
+/*
+ * Do a DRAM ECC write. Assemble staged values in the pvt area and format into
+ * fields needed by the injection registers.
+ */
+static ssize_t amd64_inject_write_store(struct mem_ctl_info *mci,
+                                       const char *data, size_t count)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       unsigned long value;
+       u32 section, word_bits;
+       int ret = 0;
+
+       ret = strict_strtoul(data, 10, &value);
+       if (ret != -EINVAL) {
+
+               /* Form value to choose 16-byte section of cacheline */
+               section = F10_NB_ARRAY_DRAM_ECC |
+                               SET_NB_ARRAY_ADDRESS(pvt->injection.section);
+               pci_write_config_dword(pvt->misc_f3_ctl,
+                                       F10_NB_ARRAY_ADDR, section);
+
+               word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection.word,
+                                               pvt->injection.bit_map);
+
+               /* Issue 'word' and 'bit' along with the READ request */
+               pci_write_config_dword(pvt->misc_f3_ctl,
+                                       F10_NB_ARRAY_DATA, word_bits);
+
+               debugf0("section=0x%x word_bits=0x%x\n", section, word_bits);
+
+               return count;
+       }
+       return ret;
+}
+
+/*
+ * update NUM_INJ_ATTRS in case you add new members
+ */
+struct mcidev_sysfs_attribute amd64_inj_attrs[] = {
+
+       {
+               .attr = {
+                       .name = "inject_section",
+                       .mode = (S_IRUGO | S_IWUSR)
+               },
+               .show = NULL,
+               .store = amd64_inject_section_store,
+       },
+       {
+               .attr = {
+                       .name = "inject_word",
+                       .mode = (S_IRUGO | S_IWUSR)
+               },
+               .show = NULL,
+               .store = amd64_inject_word_store,
+       },
+       {
+               .attr = {
+                       .name = "inject_ecc_vector",
+                       .mode = (S_IRUGO | S_IWUSR)
+               },
+               .show = NULL,
+               .store = amd64_inject_ecc_vector_store,
+       },
+       {
+               .attr = {
+                       .name = "inject_write",
+                       .mode = (S_IRUGO | S_IWUSR)
+               },
+               .show = NULL,
+               .store = amd64_inject_write_store,
+       },
+       {
+               .attr = {
+                       .name = "inject_read",
+                       .mode = (S_IRUGO | S_IWUSR)
+               },
+               .show = NULL,
+               .store = amd64_inject_read_store,
+       },
+};
index 6ad95c8d636315960d392be226078a9b13796cc6..48d3b1409834e90e705608934ec8f399974b475a 100644 (file)
 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); \
+#define edac_debug_printk(level, fmt, arg...)                           \
+       do {                                                            \
+               if (level <= edac_debug_level)                          \
+                       edac_printk(KERN_DEBUG, EDAC_DEBUG,             \
+                                   "%s: " fmt, __func__, ##arg);       \
        } while (0)
 #else  /* CONFIG_EDAC_DEBUG_VERBOSE */
 #define edac_debug_printk(level, fmt, arg...)                            \
index baa28b73ae423492412192bdf7b1b203bdf89905..b9680f50f541b76824bbe2881c60b2d4e6486f03 100644 (file)
@@ -396,7 +396,7 @@ static int __devinit calc_CCR(unsigned long scl_hz)
        signed char cdf, cdfm;
        int scgd, scgdm, scgds;
 
-       mclk = clk_get(NULL, "module_clk");
+       mclk = clk_get(NULL, "peripheral_clk");
        if (IS_ERR(mclk)) {
                return PTR_ERR(mclk);
        } else {
index 537da1cde16d6aa00c21d5b51d9c73aa6a7c71fa..e59b6dee9ae24e79196309a6c2031216b1924448 100644 (file)
@@ -402,27 +402,23 @@ static u8 ali_cable_detect(ide_hwif_t *hwif)
        return cbl;
 }
 
-#if !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC)
+#ifndef CONFIG_SPARC64
 /**
  *     init_hwif_ali15x3       -       Initialize the ALI IDE x86 stuff
  *     @hwif: interface to configure
  *
  *     Obtain the IRQ tables for an ALi based IDE solution on the PC
  *     class platforms. This part of the code isn't applicable to the
- *     Sparc and PowerPC systems.
+ *     Sparc systems.
  */
 
 static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif)
 {
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
        u8 ideic, inmir;
        s8 irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
                                      1, 11, 0, 12, 0, 14, 0, 15 };
        int irq = -1;
 
-       if (dev->device == PCI_DEVICE_ID_AL_M5229)
-               hwif->irq = hwif->channel ? 15 : 14;
-
        if (isa_dev) {
                /*
                 * read IDE interface control
@@ -455,7 +451,7 @@ static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif)
 }
 #else
 #define init_hwif_ali15x3 NULL
-#endif /* !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC) */
+#endif /* CONFIG_SPARC64 */
 
 /**
  *     init_dma_ali15x3        -       set up DMA on ALi15x3
index 7201b176d75b05814665096ab45fe372900fbe99..757e5956b13297f38a204740486f9907c35a0ae7 100644 (file)
@@ -79,34 +79,6 @@ void ide_init_pc(struct ide_atapi_pc *pc)
 }
 EXPORT_SYMBOL_GPL(ide_init_pc);
 
-/*
- * Generate a new packet command request in front of the request queue, before
- * the current request, so that it will be processed immediately, on the next
- * pass through the driver.
- */
-static void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk,
-                             struct ide_atapi_pc *pc, struct request *rq)
-{
-       blk_rq_init(NULL, rq);
-       rq->cmd_type = REQ_TYPE_SPECIAL;
-       rq->cmd_flags |= REQ_PREEMPT;
-       rq->buffer = (char *)pc;
-       rq->rq_disk = disk;
-
-       if (pc->req_xfer) {
-               rq->data = pc->buf;
-               rq->data_len = pc->req_xfer;
-       }
-
-       memcpy(rq->cmd, pc->c, 12);
-       if (drive->media == ide_tape)
-               rq->cmd[13] = REQ_IDETAPE_PC1;
-
-       drive->hwif->rq = NULL;
-
-       elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0);
-}
-
 /*
  * Add a special packet command request to the tail of the request queue,
  * and wait for it to be serviced.
@@ -119,19 +91,21 @@ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk,
 
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
        rq->cmd_type = REQ_TYPE_SPECIAL;
-       rq->buffer = (char *)pc;
+       rq->special = (char *)pc;
 
        if (pc->req_xfer) {
-               rq->data = pc->buf;
-               rq->data_len = pc->req_xfer;
+               error = blk_rq_map_kern(drive->queue, rq, pc->buf, pc->req_xfer,
+                                       GFP_NOIO);
+               if (error)
+                       goto put_req;
        }
 
        memcpy(rq->cmd, pc->c, 12);
        if (drive->media == ide_tape)
                rq->cmd[13] = REQ_IDETAPE_PC1;
        error = blk_execute_rq(drive->queue, disk, rq, 0);
+put_req:
        blk_put_request(rq);
-
        return error;
 }
 EXPORT_SYMBOL_GPL(ide_queue_pc_tail);
@@ -191,20 +165,113 @@ void ide_create_request_sense_cmd(ide_drive_t *drive, struct ide_atapi_pc *pc)
 }
 EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd);
 
+void ide_prep_sense(ide_drive_t *drive, struct request *rq)
+{
+       struct request_sense *sense = &drive->sense_data;
+       struct request *sense_rq = &drive->sense_rq;
+       unsigned int cmd_len, sense_len;
+       int err;
+
+       debug_log("%s: enter\n", __func__);
+
+       switch (drive->media) {
+       case ide_floppy:
+               cmd_len = 255;
+               sense_len = 18;
+               break;
+       case ide_tape:
+               cmd_len = 20;
+               sense_len = 20;
+               break;
+       default:
+               cmd_len = 18;
+               sense_len = 18;
+       }
+
+       BUG_ON(sense_len > sizeof(*sense));
+
+       if (blk_sense_request(rq) || drive->sense_rq_armed)
+               return;
+
+       memset(sense, 0, sizeof(*sense));
+
+       blk_rq_init(rq->q, sense_rq);
+
+       err = blk_rq_map_kern(drive->queue, sense_rq, sense, sense_len,
+                             GFP_NOIO);
+       if (unlikely(err)) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING "%s: failed to map sense buffer\n",
+                              drive->name);
+               return;
+       }
+
+       sense_rq->rq_disk = rq->rq_disk;
+       sense_rq->cmd[0] = GPCMD_REQUEST_SENSE;
+       sense_rq->cmd[4] = cmd_len;
+       sense_rq->cmd_type = REQ_TYPE_SENSE;
+       sense_rq->cmd_flags |= REQ_PREEMPT;
+
+       if (drive->media == ide_tape)
+               sense_rq->cmd[13] = REQ_IDETAPE_PC1;
+
+       drive->sense_rq_armed = true;
+}
+EXPORT_SYMBOL_GPL(ide_prep_sense);
+
+int ide_queue_sense_rq(ide_drive_t *drive, void *special)
+{
+       /* deferred failure from ide_prep_sense() */
+       if (!drive->sense_rq_armed) {
+               printk(KERN_WARNING "%s: failed queue sense request\n",
+                      drive->name);
+               return -ENOMEM;
+       }
+
+       drive->sense_rq.special = special;
+       drive->sense_rq_armed = false;
+
+       drive->hwif->rq = NULL;
+
+       elv_add_request(drive->queue, &drive->sense_rq,
+                       ELEVATOR_INSERT_FRONT, 0);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ide_queue_sense_rq);
+
 /*
  * Called when an error was detected during the last packet command.
- * We queue a request sense packet command in the head of the request list.
+ * We queue a request sense packet command at the head of the request
+ * queue.
  */
-void ide_retry_pc(ide_drive_t *drive, struct gendisk *disk)
+void ide_retry_pc(ide_drive_t *drive)
 {
-       struct request *rq = &drive->request_sense_rq;
+       struct request *failed_rq = drive->hwif->rq;
+       struct request *sense_rq = &drive->sense_rq;
        struct ide_atapi_pc *pc = &drive->request_sense_pc;
 
        (void)ide_read_error(drive);
-       ide_create_request_sense_cmd(drive, pc);
+
+       /* init pc from sense_rq */
+       ide_init_pc(pc);
+       memcpy(pc->c, sense_rq->cmd, 12);
+       pc->buf = bio_data(sense_rq->bio);      /* pointer to mapped address */
+       pc->req_xfer = blk_rq_bytes(sense_rq);
+
        if (drive->media == ide_tape)
                set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
-       ide_queue_pc_head(drive, disk, pc, rq);
+
+       /*
+        * Push back the failed request and put request sense on top
+        * of it.  The failed command will be retried after sense data
+        * is acquired.
+        */
+       blk_requeue_request(failed_rq->q, failed_rq);
+       drive->hwif->rq = NULL;
+       if (ide_queue_sense_rq(drive, pc)) {
+               blk_start_request(failed_rq);
+               ide_complete_rq(drive, -EIO, blk_rq_bytes(failed_rq));
+       }
 }
 EXPORT_SYMBOL_GPL(ide_retry_pc);
 
@@ -246,7 +313,7 @@ int ide_cd_get_xferlen(struct request *rq)
                return 32768;
        else if (blk_sense_request(rq) || blk_pc_request(rq) ||
                         rq->cmd_type == REQ_TYPE_ATA_PC)
-               return rq->data_len;
+               return blk_rq_bytes(rq);
        else
                return 0;
 }
@@ -276,7 +343,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
        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, done;
        u16 bcount;
        u8 stat, ireason, dsc = 0;
@@ -303,18 +369,14 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                                        drive->name, rq_data_dir(pc->rq)
                                                     ? "write" : "read");
                        pc->flags |= PC_FLAG_DMA_ERROR;
-               } else {
+               } else
                        pc->xferred = pc->req_xfer;
-                       if (drive->pc_update_buffers)
-                               drive->pc_update_buffers(drive, pc);
-               }
                debug_log("%s: DMA finished\n", drive->name);
        }
 
        /* No more interrupts */
        if ((stat & ATA_DRQ) == 0) {
                int uptodate, error;
-               unsigned int done;
 
                debug_log("Packet command completed, %d bytes transferred\n",
                          pc->xferred);
@@ -343,7 +405,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                        debug_log("[cmd %x]: check condition\n", rq->cmd[0]);
 
                        /* Retry operation */
-                       ide_retry_pc(drive, rq->rq_disk);
+                       ide_retry_pc(drive);
 
                        /* queued, but not started */
                        return ide_stopped;
@@ -353,6 +415,12 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0)
                        dsc = 1;
 
+               /*
+                * ->pc_callback() might change rq->data_len for
+                * residual count, cache total length.
+                */
+               done = blk_rq_bytes(rq);
+
                /* Command finished - Call the callback function */
                uptodate = drive->pc_callback(drive, dsc);
 
@@ -361,7 +429,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
 
                if (blk_special_request(rq)) {
                        rq->errors = 0;
-                       done = blk_rq_bytes(rq);
                        error = 0;
                } else {
 
@@ -370,15 +437,10 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                                        rq->errors = -EIO;
                        }
 
-                       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);
+               ide_complete_rq(drive, error, blk_rq_bytes(rq));
                return ide_stopped;
        }
 
@@ -407,21 +469,11 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                return ide_do_reset(drive);
        }
 
-       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);
-       }
+       done = min_t(unsigned int, bcount, cmd->nleft);
+       ide_pio_bytes(drive, cmd, write, done);
 
-       /* Update the current position */
+       /* Update transferred byte count */
        pc->xferred += done;
-       pc->cur_pos += done;
 
        bcount -= done;
 
@@ -599,7 +651,6 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd)
 
                /* We haven't transferred any data yet */
                pc->xferred = 0;
-               pc->cur_pos = pc->buf;
 
                valid_tf = IDE_VALID_DEVICE;
                bcount = ((drive->media == ide_tape) ?
index 925eb9e245d1e7f0028dbc3cd0e698bce6b98962..424140c6c400e6f524c91f72758cb7fb59816b4f 100644 (file)
@@ -182,7 +182,7 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive,
                                 (sense->information[2] <<  8) |
                                 (sense->information[3]);
 
-                       if (drive->queue->hardsect_size == 2048)
+                       if (queue_logical_block_size(drive->queue) == 2048)
                                /* device sector size is 2K */
                                sector <<= 2;
 
@@ -206,54 +206,25 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive,
        ide_cd_log_error(drive->name, failed_command, sense);
 }
 
-static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
-                                     struct request *failed_command)
-{
-       struct cdrom_info *info         = drive->driver_data;
-       struct request *rq              = &drive->request_sense_rq;
-
-       ide_debug_log(IDE_DBG_SENSE, "enter");
-
-       if (sense == NULL)
-               sense = &info->sense_data;
-
-       /* stuff the sense request in front of our current request */
-       blk_rq_init(NULL, rq);
-       rq->cmd_type = REQ_TYPE_ATA_PC;
-       rq->rq_disk = info->disk;
-
-       rq->data = sense;
-       rq->cmd[0] = GPCMD_REQUEST_SENSE;
-       rq->cmd[4] = 18;
-       rq->data_len = 18;
-
-       rq->cmd_type = REQ_TYPE_SENSE;
-       rq->cmd_flags |= REQ_PREEMPT;
-
-       /* NOTE! Save the failed command in "rq->buffer" */
-       rq->buffer = (void *) failed_command;
-
-       if (failed_command)
-               ide_debug_log(IDE_DBG_SENSE, "failed_cmd: 0x%x",
-                                            failed_command->cmd[0]);
-
-       drive->hwif->rq = NULL;
-
-       elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0);
-}
-
 static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq)
 {
        /*
-        * For REQ_TYPE_SENSE, "rq->buffer" points to the original
-        * failed request
+        * For REQ_TYPE_SENSE, "rq->special" points to the original
+        * failed request.  Also, the sense data should be read
+        * directly from rq which might be different from the original
+        * sense buffer if it got copied during mapping.
         */
-       struct request *failed = (struct request *)rq->buffer;
-       struct cdrom_info *info = drive->driver_data;
-       void *sense = &info->sense_data;
+       struct request *failed = (struct request *)rq->special;
+       void *sense = bio_data(rq->bio);
 
        if (failed) {
                if (failed->sense) {
+                       /*
+                        * Sense is always read into drive->sense_data.
+                        * Copy back if the failed request has its
+                        * sense pointer set.
+                        */
+                       memcpy(failed->sense, sense, 18);
                        sense = failed->sense;
                        failed->sense_len = rq->sense_len;
                }
@@ -428,22 +399,13 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
 
        /* if we got a CHECK_CONDITION status, queue a request sense command */
        if (stat & ATA_ERR)
-               cdrom_queue_request_sense(drive, NULL, NULL);
+               return ide_queue_sense_rq(drive, NULL) ? 2 : 1;
        return 1;
 
 end_request:
        if (stat & ATA_ERR) {
-               struct request_queue *q = drive->queue;
-               unsigned long flags;
-
-               spin_lock_irqsave(q->queue_lock, flags);
-               blkdev_dequeue_request(rq);
-               spin_unlock_irqrestore(q->queue_lock, flags);
-
                hwif->rq = NULL;
-
-               cdrom_queue_request_sense(drive, rq->sense, rq);
-               return 1;
+               return ide_queue_sense_rq(drive, rq) ? 2 : 1;
        } else
                return 2;
 }
@@ -503,14 +465,8 @@ static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd)
         * and some drives don't send them.  Sigh.
         */
        if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
-           cmd->nleft > 0 && cmd->nleft <= 5) {
-               unsigned int ofs = cmd->nbytes - cmd->nleft;
-
-               while (cmd->nleft > 0) {
-                       *((u8 *)rq->data + ofs++) = 0;
-                       cmd->nleft--;
-               }
-       }
+           cmd->nleft > 0 && cmd->nleft <= 5)
+               cmd->nleft = 0;
 }
 
 int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
@@ -543,14 +499,18 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
                rq->cmd_flags |= cmd_flags;
                rq->timeout = timeout;
                if (buffer) {
-                       rq->data = buffer;
-                       rq->data_len = *bufflen;
+                       error = blk_rq_map_kern(drive->queue, rq, buffer,
+                                               *bufflen, GFP_NOIO);
+                       if (error) {
+                               blk_put_request(rq);
+                               return error;
+                       }
                }
 
                error = blk_execute_rq(drive->queue, info->disk, rq, 0);
 
                if (buffer)
-                       *bufflen = rq->data_len;
+                       *bufflen = rq->resid_len;
 
                flags = rq->cmd_flags;
                blk_put_request(rq);
@@ -608,7 +568,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        struct request *rq = hwif->rq;
        ide_expiry_t *expiry = NULL;
        int dma_error = 0, dma, thislen, uptodate = 0;
-       int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc = 0, nsectors;
+       int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc = 0;
        int sense = blk_sense_request(rq);
        unsigned int timeout;
        u16 len;
@@ -738,13 +698,8 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 
 out_end:
        if (blk_pc_request(rq) && rc == 0) {
-               unsigned int dlen = rq->data_len;
-
-               rq->data_len = 0;
-
-               if (blk_end_request(rq, 0, dlen))
-                       BUG();
-
+               rq->resid_len = 0;
+               blk_end_request_all(rq, 0);
                hwif->rq = NULL;
        } else {
                if (sense && uptodate)
@@ -762,21 +717,13 @@ out_end:
                        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);
+                       rq->resid_len -= cmd->nbytes - cmd->nleft;
                        if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE))
-                               rq->data_len += cmd->last_xfer_len;
+                               rq->resid_len += cmd->last_xfer_len;
                }
 
-               ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9);
+               ide_complete_rq(drive, uptodate ? 0 : -EIO, blk_rq_bytes(rq));
 
                if (sense && rc == 2)
                        ide_error(drive, "request sense failure", stat);
@@ -790,7 +737,7 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
        struct request_queue *q = drive->queue;
        int write = rq_data_dir(rq) == WRITE;
        unsigned short sectors_per_frame =
-               queue_hardsect_size(q) >> SECTOR_BITS;
+               queue_logical_block_size(q) >> SECTOR_BITS;
 
        ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, "
                                  "secs_per_frame: %u",
@@ -809,8 +756,8 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
        }
 
        /* fs requests *must* be hardware frame aligned */
-       if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
-           (rq->sector & (sectors_per_frame - 1)))
+       if ((blk_rq_sectors(rq) & (sectors_per_frame - 1)) ||
+           (blk_rq_pos(rq) & (sectors_per_frame - 1)))
                return ide_stopped;
 
        /* use DMA, if possible */
@@ -838,15 +785,10 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
        drive->dma = 0;
 
        /* sg request */
-       if (rq->bio || ((rq->cmd_type == REQ_TYPE_ATA_PC) && rq->data_len)) {
+       if (rq->bio) {
                struct request_queue *q = drive->queue;
+               char *buf = bio_data(rq->bio);
                unsigned int alignment;
-               char *buf;
-
-               if (rq->bio)
-                       buf = bio_data(rq->bio);
-               else
-                       buf = rq->data;
 
                drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
 
@@ -858,7 +800,7 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
                 */
                alignment = queue_dma_alignment(q) | q->dma_pad_mask;
                if ((unsigned long)buf & alignment
-                   || rq->data_len & q->dma_pad_mask
+                   || blk_rq_bytes(rq) & q->dma_pad_mask
                    || object_is_on_stack(buf))
                        drive->dma = 0;
        }
@@ -896,6 +838,9 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
                goto out_end;
        }
 
+       /* prepare sense request for this command */
+       ide_prep_sense(drive, rq);
+
        memset(&cmd, 0, sizeof(cmd));
 
        if (rq_data_dir(rq))
@@ -903,15 +848,14 @@ 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);
+       if (blk_fs_request(rq) || blk_rq_bytes(rq)) {
+               ide_init_sg_cmd(&cmd, blk_rq_bytes(rq));
                ide_map_sg(drive, &cmd);
        }
 
        return ide_issue_pc(drive, &cmd);
 out_end:
-       nsectors = rq->hard_nr_sectors;
+       nsectors = blk_rq_sectors(rq);
 
        if (nsectors == 0)
                nsectors = 1;
@@ -1077,8 +1021,8 @@ int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense)
        /* save a private copy of the TOC capacity for error handling */
        drive->probed_capacity = toc->capacity * sectors_per_frame;
 
-       blk_queue_hardsect_size(drive->queue,
-                               sectors_per_frame << SECTOR_BITS);
+       blk_queue_logical_block_size(drive->queue,
+                                    sectors_per_frame << SECTOR_BITS);
 
        /* first read just the header, so we know how long the TOC is */
        stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr,
@@ -1394,9 +1338,9 @@ static int ide_cdrom_probe_capabilities(ide_drive_t *drive)
 /* standard prep_rq_fn that builds 10 byte cmds */
 static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq)
 {
-       int hard_sect = queue_hardsect_size(q);
-       long block = (long)rq->hard_sector / (hard_sect >> 9);
-       unsigned long blocks = rq->hard_nr_sectors / (hard_sect >> 9);
+       int hard_sect = queue_logical_block_size(q);
+       long block = (long)blk_rq_pos(rq) / (hard_sect >> 9);
+       unsigned long blocks = blk_rq_sectors(rq) / (hard_sect >> 9);
 
        memset(rq->cmd, 0, BLK_MAX_CDB);
 
@@ -1599,7 +1543,7 @@ static int ide_cdrom_setup(ide_drive_t *drive)
 
        nslots = ide_cdrom_probe_capabilities(drive);
 
-       blk_queue_hardsect_size(q, CD_FRAMESIZE);
+       blk_queue_logical_block_size(q, CD_FRAMESIZE);
 
        if (ide_cdrom_register(drive, nslots)) {
                printk(KERN_ERR PFX "%s: %s failed to register device with the"
index 1d97101099ce20bab8e0b319f6da278a09bd9afa..93a3cf1b0f3f8c61b974b9b16a190502f5d4d038 100644 (file)
@@ -87,10 +87,6 @@ struct cdrom_info {
 
        struct atapi_toc *toc;
 
-       /* The result of the last successful request sense command
-          on this device. */
-       struct request_sense sense_data;
-
        u8 max_speed;           /* Max speed of the drive. */
        u8 current_speed;       /* Current speed of the drive. */
 
index a9fbe2c31210cc1400dc2ce132c74211dbd40642..c6f7fcfb9d672f47fb585fc035a1ee9f74f9642d 100644 (file)
@@ -82,7 +82,7 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
                                        sector_t block)
 {
        ide_hwif_t *hwif        = drive->hwif;
-       u16 nsectors            = (u16)rq->nr_sectors;
+       u16 nsectors            = (u16)blk_rq_sectors(rq);
        u8 lba48                = !!(drive->dev_flags & IDE_DFLAG_LBA48);
        u8 dma                  = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
        struct ide_cmd          cmd;
@@ -90,7 +90,7 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
        ide_startstop_t         rc;
 
        if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
-               if (block + rq->nr_sectors > 1ULL << 28)
+               if (block + blk_rq_sectors(rq) > 1ULL << 28)
                        dma = 0;
                else
                        lba48 = 0;
@@ -195,9 +195,9 @@ static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
 
        ledtrig_ide_activity();
 
-       pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n",
+       pr_debug("%s: %sing: block=%llu, sectors=%u, buffer=0x%08lx\n",
                 drive->name, rq_data_dir(rq) == READ ? "read" : "writ",
-                (unsigned long long)block, rq->nr_sectors,
+                (unsigned long long)block, blk_rq_sectors(rq),
                 (unsigned long)rq->buffer);
 
        if (hwif->rw_disk)
@@ -411,7 +411,6 @@ static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
        cmd->protocol = ATA_PROT_NODATA;
 
        rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
-       rq->cmd_flags |= REQ_SOFTBARRIER;
        rq->special = cmd;
 }
 
@@ -640,7 +639,7 @@ static void ide_disk_setup(ide_drive_t *drive)
        }
 
        printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name,
-               q->max_sectors / 2);
+              queue_max_sectors(q) / 2);
 
        if (ata_id_is_ssd(id))
                queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
index a0b8cab1d9a682249200fce35bc5ea5c8223079f..001f68f0bb285c62d0b42b6dbb1508d92182923a 100644 (file)
@@ -103,7 +103,7 @@ ide_startstop_t ide_dma_intr(ide_drive_t *drive)
                                ide_finish_cmd(drive, cmd, stat);
                        else
                                ide_complete_rq(drive, 0,
-                                               cmd->rq->nr_sectors << 9);
+                                               blk_rq_sectors(cmd->rq) << 9);
                        return ide_stopped;
                }
                printk(KERN_ERR "%s: %s: bad DMA status (0x%02x)\n",
@@ -510,23 +510,11 @@ ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
        /*
         * un-busy drive etc and make sure request is sane
         */
-
        rq = hwif->rq;
-       if (!rq)
-               goto out;
-
-       hwif->rq = NULL;
-
-       rq->errors = 0;
-
-       if (!rq->bio)
-               goto out;
-
-       rq->sector = rq->bio->bi_sector;
-       rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
-       rq->hard_cur_sectors = rq->current_nr_sectors;
-       rq->buffer = bio_data(rq->bio);
-out:
+       if (rq) {
+               hwif->rq = NULL;
+               rq->errors = 0;
+       }
        return ret;
 }
 
index 2b4868d95f8b0597de827c36df575cec1375d8f7..650981758f15cd0b83e05d455cb590a61401edf4 100644 (file)
@@ -134,13 +134,17 @@ static ide_startstop_t ide_floppy_issue_pc(ide_drive_t *drive,
        drive->pc = pc;
 
        if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) {
+               unsigned int done = blk_rq_bytes(drive->hwif->rq);
+
                if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR))
                        ide_floppy_report_error(floppy, pc);
+
                /* Giving up */
                pc->error = IDE_DRV_ERROR_GENERAL;
 
                drive->failed_pc = NULL;
                drive->pc_callback(drive, 0);
+               ide_complete_rq(drive, -EIO, done);
                return ide_stopped;
        }
 
@@ -190,7 +194,7 @@ static void idefloppy_create_rw_cmd(ide_drive_t *drive,
 {
        struct ide_disk_obj *floppy = drive->driver_data;
        int block = sector / floppy->bs_factor;
-       int blocks = rq->nr_sectors / floppy->bs_factor;
+       int blocks = blk_rq_sectors(rq) / floppy->bs_factor;
        int cmd = rq_data_dir(rq);
 
        ide_debug_log(IDE_DBG_FUNC, "block: %d, blocks: %d", block, blocks);
@@ -216,16 +220,14 @@ 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;
-       if (rq->data_len && rq_data_dir(rq) == WRITE)
-               pc->flags |= PC_FLAG_WRITING;
-       pc->buf = rq->data;
-       if (rq->bio)
+       if (blk_rq_bytes(rq)) {
                pc->flags |= PC_FLAG_DMA_OK;
-       /*
-        * possibly problematic, doesn't look like ide-floppy correctly
-        * handled scattered requests if dma fails...
-        */
-       pc->req_xfer = pc->buf_size = rq->data_len;
+               if (rq_data_dir(rq) == WRITE)
+                       pc->flags |= PC_FLAG_WRITING;
+       }
+       /* pio will be performed by ide_pio_bytes() which handles sg fine */
+       pc->buf = NULL;
+       pc->req_xfer = pc->buf_size = blk_rq_bytes(rq);
 }
 
 static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
@@ -257,16 +259,16 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
                        goto out_end;
        }
        if (blk_fs_request(rq)) {
-               if (((long)rq->sector % floppy->bs_factor) ||
-                   (rq->nr_sectors % floppy->bs_factor)) {
+               if (((long)blk_rq_pos(rq) % floppy->bs_factor) ||
+                   (blk_rq_sectors(rq) % floppy->bs_factor)) {
                        printk(KERN_ERR PFX "%s: unsupported r/w rq size\n",
                                drive->name);
                        goto out_end;
                }
                pc = &floppy->queued_pc;
                idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block);
-       } else if (blk_special_request(rq)) {
-               pc = (struct ide_atapi_pc *) rq->buffer;
+       } else if (blk_special_request(rq) || blk_sense_request(rq)) {
+               pc = (struct ide_atapi_pc *)rq->special;
        } else if (blk_pc_request(rq)) {
                pc = &floppy->queued_pc;
                idefloppy_blockpc_cmd(floppy, pc, rq);
@@ -275,6 +277,8 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
                goto out_end;
        }
 
+       ide_prep_sense(drive, rq);
+
        memset(&cmd, 0, sizeof(cmd));
 
        if (rq_data_dir(rq))
index 6415a2e2ba87febae0cfa6e9b8342f2dbd190748..bba4297f2f03fcadf80f8bb3f3a05e780e6f3551 100644 (file)
@@ -116,9 +116,9 @@ void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err)
 unsigned int ide_rq_bytes(struct request *rq)
 {
        if (blk_pc_request(rq))
-               return rq->data_len;
+               return blk_rq_bytes(rq);
        else
-               return rq->hard_cur_sectors << 9;
+               return blk_rq_cur_sectors(rq) << 9;
 }
 EXPORT_SYMBOL_GPL(ide_rq_bytes);
 
@@ -133,7 +133,7 @@ int ide_complete_rq(ide_drive_t *drive, int error, unsigned int nr_bytes)
         * and complete the whole request right now
         */
        if (blk_noretry_request(rq) && error <= 0)
-               nr_bytes = rq->hard_nr_sectors << 9;
+               nr_bytes = blk_rq_sectors(rq) << 9;
 
        rc = ide_end_rq(drive, rq, error, nr_bytes);
        if (rc == 0)
@@ -248,14 +248,7 @@ void ide_map_sg(ide_drive_t *drive, struct ide_cmd *cmd)
        struct scatterlist *sg = hwif->sg_table;
        struct request *rq = cmd->rq;
 
-       if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-               sg_init_one(sg, rq->buffer, rq->nr_sectors * SECTOR_SIZE);
-               cmd->sg_nents = 1;
-       } else if (!rq->bio) {
-               sg_init_one(sg, rq->data, rq->data_len);
-               cmd->sg_nents = 1;
-       } else
-               cmd->sg_nents = blk_rq_map_sg(drive->queue, rq, sg);
+       cmd->sg_nents = blk_rq_map_sg(drive->queue, rq, sg);
 }
 EXPORT_SYMBOL_GPL(ide_map_sg);
 
@@ -286,7 +279,7 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
 
        if (cmd) {
                if (cmd->protocol == ATA_PROT_PIO) {
-                       ide_init_sg_cmd(cmd, rq->nr_sectors << 9);
+                       ide_init_sg_cmd(cmd, blk_rq_sectors(rq) << 9);
                        ide_map_sg(drive, cmd);
                }
 
@@ -371,7 +364,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
                if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
                        return execute_drive_cmd(drive, rq);
                else if (blk_pm_request(rq)) {
-                       struct request_pm_state *pm = rq->data;
+                       struct request_pm_state *pm = rq->special;
 #ifdef DEBUG_PM
                        printk("%s: start_power_step(step: %d)\n",
                                drive->name, pm->pm_step);
@@ -394,7 +387,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
 
                drv = *(struct ide_driver **)rq->rq_disk->private_data;
 
-               return drv->do_request(drive, rq, rq->sector);
+               return drv->do_request(drive, rq, blk_rq_pos(rq));
        }
        return do_special(drive);
 kill_rq:
@@ -484,6 +477,9 @@ void do_ide_request(struct request_queue *q)
 
        spin_unlock_irq(q->queue_lock);
 
+       /* HLD do_request() callback might sleep, make sure it's okay */
+       might_sleep();
+
        if (ide_lock_host(host, hwif))
                goto plug_device_2;
 
@@ -491,10 +487,10 @@ void do_ide_request(struct request_queue *q)
 
        if (!ide_lock_port(hwif)) {
                ide_hwif_t *prev_port;
+
+               WARN_ON_ONCE(hwif->rq);
 repeat:
                prev_port = hwif->host->cur_port;
-               hwif->rq = NULL;
-
                if (drive->dev_flags & IDE_DFLAG_SLEEPING &&
                    time_after(drive->sleep, jiffies)) {
                        ide_unlock_port(hwif);
@@ -523,7 +519,9 @@ repeat:
                 * we know that the queue isn't empty, but this can happen
                 * if the q->prep_rq_fn() decides to kill a request
                 */
-               rq = elv_next_request(drive->queue);
+               if (!rq)
+                       rq = blk_fetch_request(drive->queue);
+
                spin_unlock_irq(q->queue_lock);
                spin_lock_irq(&hwif->lock);
 
@@ -535,7 +533,7 @@ repeat:
                /*
                 * Sanity: don't accept a request that isn't a PM request
                 * if we are currently power managed. This is very important as
-                * blk_stop_queue() doesn't prevent the elv_next_request()
+                * blk_stop_queue() doesn't prevent the blk_fetch_request()
                 * above to return us whatever is in the queue. Since we call
                 * ide_do_request() ourselves, we end up taking requests while
                 * the queue is blocked...
@@ -559,8 +557,11 @@ repeat:
                startstop = start_request(drive, rq);
                spin_lock_irq(&hwif->lock);
 
-               if (startstop == ide_stopped)
+               if (startstop == ide_stopped) {
+                       rq = hwif->rq;
+                       hwif->rq = NULL;
                        goto repeat;
+               }
        } else
                goto plug_device;
 out:
@@ -576,18 +577,24 @@ plug_device:
 plug_device_2:
        spin_lock_irq(q->queue_lock);
 
+       if (rq)
+               blk_requeue_request(q, rq);
        if (!elv_queue_empty(q))
                blk_plug_device(q);
 }
 
-static void ide_plug_device(ide_drive_t *drive)
+static void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq)
 {
        struct request_queue *q = drive->queue;
        unsigned long flags;
 
        spin_lock_irqsave(q->queue_lock, flags);
+
+       if (rq)
+               blk_requeue_request(q, rq);
        if (!elv_queue_empty(q))
                blk_plug_device(q);
+
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
@@ -636,6 +643,7 @@ void ide_timer_expiry (unsigned long data)
        unsigned long   flags;
        int             wait = -1;
        int             plug_device = 0;
+       struct request  *uninitialized_var(rq_in_flight);
 
        spin_lock_irqsave(&hwif->lock, flags);
 
@@ -697,6 +705,8 @@ void ide_timer_expiry (unsigned long data)
                spin_lock_irq(&hwif->lock);
                enable_irq(hwif->irq);
                if (startstop == ide_stopped && hwif->polling == 0) {
+                       rq_in_flight = hwif->rq;
+                       hwif->rq = NULL;
                        ide_unlock_port(hwif);
                        plug_device = 1;
                }
@@ -705,7 +715,7 @@ void ide_timer_expiry (unsigned long data)
 
        if (plug_device) {
                ide_unlock_host(hwif->host);
-               ide_plug_device(drive);
+               ide_requeue_and_plug(drive, rq_in_flight);
        }
 }
 
@@ -791,6 +801,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
        ide_startstop_t startstop;
        irqreturn_t irq_ret = IRQ_NONE;
        int plug_device = 0;
+       struct request *uninitialized_var(rq_in_flight);
 
        if (host->host_flags & IDE_HFLAG_SERIALIZE) {
                if (hwif != host->cur_port)
@@ -870,6 +881,8 @@ irqreturn_t ide_intr (int irq, void *dev_id)
         */
        if (startstop == ide_stopped && hwif->polling == 0) {
                BUG_ON(hwif->handler);
+               rq_in_flight = hwif->rq;
+               hwif->rq = NULL;
                ide_unlock_port(hwif);
                plug_device = 1;
        }
@@ -879,7 +892,7 @@ out:
 out_early:
        if (plug_device) {
                ide_unlock_host(hwif->host);
-               ide_plug_device(drive);
+               ide_requeue_and_plug(drive, rq_in_flight);
        }
 
        return irq_ret;
index c1c25ebbaa1fb3ef6abac4bb720946bfd6af90c6..5991b23793f20ee33f164a2dea752804f7580310 100644 (file)
@@ -231,7 +231,6 @@ static int generic_drive_reset(ide_drive_t *drive)
        rq->cmd_type = REQ_TYPE_SPECIAL;
        rq->cmd_len = 1;
        rq->cmd[0] = REQ_DRIVE_RESET;
-       rq->cmd_flags |= REQ_SOFTBARRIER;
        if (blk_execute_rq(drive->queue, NULL, rq, 1))
                ret = rq->errors;
        blk_put_request(rq);
index 2148df836ce7f19f48b8ed26f8ae3f01b4700ff5..e386a32dc9ba888c110b42971d57a1bab2662f49 100644 (file)
@@ -96,7 +96,7 @@ static void ide_dump_ata_error(ide_drive_t *drive, u8 err)
 
                if (rq)
                        printk(KERN_CONT ", sector=%llu",
-                              (unsigned long long)rq->sector);
+                              (unsigned long long)blk_rq_pos(rq));
        }
        printk(KERN_CONT "\n");
 }
index 310d03f2b5b793e456305547ffd3d86e036c66ca..a914023d6d035d9e530178ff2422a7bf386cc2cd 100644 (file)
@@ -24,11 +24,8 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
                        start_queue = 1;
                spin_unlock_irq(&hwif->lock);
 
-               if (start_queue) {
-                       spin_lock_irq(q->queue_lock);
-                       blk_start_queueing(q);
-                       spin_unlock_irq(q->queue_lock);
-               }
+               if (start_queue)
+                       blk_run_queue(q);
                return;
        }
        spin_unlock_irq(&hwif->lock);
index 0d8a151c0a01da799d0c68f96b20dc2dbe1928bc..ba1488bd84307bb90850977573d2e80c9778af69 100644 (file)
@@ -7,7 +7,6 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq;
        struct request_pm_state rqpm;
-       struct ide_cmd cmd;
        int ret;
 
        /* call ACPI _GTM only once */
@@ -15,11 +14,9 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
                ide_acpi_get_timing(hwif);
 
        memset(&rqpm, 0, sizeof(rqpm));
-       memset(&cmd, 0, sizeof(cmd));
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
        rq->cmd_type = REQ_TYPE_PM_SUSPEND;
-       rq->special = &cmd;
-       rq->data = &rqpm;
+       rq->special = &rqpm;
        rqpm.pm_step = IDE_PM_START_SUSPEND;
        if (mesg.event == PM_EVENT_PRETHAW)
                mesg.event = PM_EVENT_FREEZE;
@@ -41,7 +38,6 @@ int generic_ide_resume(struct device *dev)
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq;
        struct request_pm_state rqpm;
-       struct ide_cmd cmd;
        int err;
 
        /* call ACPI _PS0 / _STM only once */
@@ -53,12 +49,10 @@ int generic_ide_resume(struct device *dev)
        ide_acpi_exec_tfs(drive);
 
        memset(&rqpm, 0, sizeof(rqpm));
-       memset(&cmd, 0, sizeof(cmd));
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
        rq->cmd_type = REQ_TYPE_PM_RESUME;
        rq->cmd_flags |= REQ_PREEMPT;
-       rq->special = &cmd;
-       rq->data = &rqpm;
+       rq->special = &rqpm;
        rqpm.pm_step = IDE_PM_START_RESUME;
        rqpm.pm_state = PM_EVENT_ON;
 
@@ -77,7 +71,7 @@ int generic_ide_resume(struct device *dev)
 
 void ide_complete_power_step(ide_drive_t *drive, struct request *rq)
 {
-       struct request_pm_state *pm = rq->data;
+       struct request_pm_state *pm = rq->special;
 
 #ifdef DEBUG_PM
        printk(KERN_INFO "%s: complete_power_step(step: %d)\n",
@@ -107,10 +101,8 @@ void ide_complete_power_step(ide_drive_t *drive, struct request *rq)
 
 ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
 {
-       struct request_pm_state *pm = rq->data;
-       struct ide_cmd *cmd = rq->special;
-
-       memset(cmd, 0, sizeof(*cmd));
+       struct request_pm_state *pm = rq->special;
+       struct ide_cmd cmd = { };
 
        switch (pm->pm_step) {
        case IDE_PM_FLUSH_CACHE:        /* Suspend step 1 (flush cache) */
@@ -123,12 +115,12 @@ ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
                        return ide_stopped;
                }
                if (ata_id_flush_ext_enabled(drive->id))
-                       cmd->tf.command = ATA_CMD_FLUSH_EXT;
+                       cmd.tf.command = ATA_CMD_FLUSH_EXT;
                else
-                       cmd->tf.command = ATA_CMD_FLUSH;
+                       cmd.tf.command = ATA_CMD_FLUSH;
                goto out_do_tf;
        case IDE_PM_STANDBY:            /* Suspend step 2 (standby) */
-               cmd->tf.command = ATA_CMD_STANDBYNOW1;
+               cmd.tf.command = ATA_CMD_STANDBYNOW1;
                goto out_do_tf;
        case IDE_PM_RESTORE_PIO:        /* Resume step 1 (restore PIO) */
                ide_set_max_pio(drive);
@@ -141,7 +133,7 @@ ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
                        ide_complete_power_step(drive, rq);
                return ide_stopped;
        case IDE_PM_IDLE:               /* Resume step 2 (idle) */
-               cmd->tf.command = ATA_CMD_IDLEIMMEDIATE;
+               cmd.tf.command = ATA_CMD_IDLEIMMEDIATE;
                goto out_do_tf;
        case IDE_PM_RESTORE_DMA:        /* Resume step 3 (restore DMA) */
                /*
@@ -163,11 +155,11 @@ ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
        return ide_stopped;
 
 out_do_tf:
-       cmd->valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-       cmd->valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-       cmd->protocol = ATA_PROT_NODATA;
+       cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
+       cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
+       cmd.protocol = ATA_PROT_NODATA;
 
-       return do_rw_taskfile(drive, cmd);
+       return do_rw_taskfile(drive, &cmd);
 }
 
 /**
@@ -181,7 +173,7 @@ out_do_tf:
 void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq)
 {
        struct request_queue *q = drive->queue;
-       struct request_pm_state *pm = rq->data;
+       struct request_pm_state *pm = rq->special;
        unsigned long flags;
 
        ide_complete_power_step(drive, rq);
@@ -207,7 +199,7 @@ void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq)
 
 void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
 {
-       struct request_pm_state *pm = rq->data;
+       struct request_pm_state *pm = rq->special;
 
        if (blk_pm_suspend_request(rq) &&
            pm->pm_step == IDE_PM_START_SUSPEND)
index 3a53e0834cf798d6bbc7c5fca982d192d1941fd3..d9764f0bc82f54e4b250c6e03754d108e2252383 100644 (file)
@@ -131,13 +131,6 @@ enum {
        IDETAPE_DIR_WRITE = (1 << 2),
 };
 
-struct idetape_bh {
-       u32 b_size;
-       atomic_t b_count;
-       struct idetape_bh *b_reqnext;
-       char *b_data;
-};
-
 /* Tape door status */
 #define DOOR_UNLOCKED                  0
 #define DOOR_LOCKED                    1
@@ -219,18 +212,12 @@ typedef struct ide_tape_obj {
 
        /* Data buffer size chosen based on the tape's recommendation */
        int buffer_size;
-       /* merge buffer */
-       struct idetape_bh *merge_bh;
-       /* size of the merge buffer */
-       int merge_bh_size;
-       /* pointer to current buffer head within the merge buffer */
-       struct idetape_bh *bh;
-       char *b_data;
-       int b_count;
-
-       int pages_per_buffer;
-       /* Wasted space in each stage */
-       int excess_bh_size;
+       /* Staging buffer of buffer_size bytes */
+       void *buf;
+       /* The read/write cursor */
+       void *cur;
+       /* The number of valid bytes in buf */
+       size_t valid;
 
        /* Measures average tape speed */
        unsigned long avg_time;
@@ -297,84 +284,6 @@ static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
        return tape;
 }
 
-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)
-                       break;
-               count = min(
-                       (unsigned int)(bh->b_size - atomic_read(&bh->b_count)),
-                       bcount);
-               drive->hwif->tp_ops->input_data(drive, NULL, bh->b_data +
-                                       atomic_read(&bh->b_count), count);
-               bcount -= count;
-               atomic_add(count, &bh->b_count);
-               if (atomic_read(&bh->b_count) == bh->b_size) {
-                       bh = bh->b_reqnext;
-                       if (bh)
-                               atomic_set(&bh->b_count, 0);
-               }
-       }
-
-       pc->bh = bh;
-
-       return bcount;
-}
-
-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)
-                       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;
-               pc->b_data += count;
-               pc->b_count -= count;
-               if (!pc->b_count) {
-                       bh = bh->b_reqnext;
-                       pc->bh = bh;
-                       if (bh) {
-                               pc->b_data = bh->b_data;
-                               pc->b_count = atomic_read(&bh->b_count);
-                       }
-               }
-       }
-
-       return bcount;
-}
-
-static void idetape_update_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc)
-{
-       struct idetape_bh *bh = pc->bh;
-       int count;
-       unsigned int bcount = pc->xferred;
-
-       if (pc->flags & PC_FLAG_WRITING)
-               return;
-       while (bcount) {
-               if (bh == NULL) {
-                       printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
-                                       __func__);
-                       return;
-               }
-               count = min((unsigned int)bh->b_size, (unsigned int)bcount);
-               atomic_set(&bh->b_count, count);
-               if (atomic_read(&bh->b_count) == bh->b_size)
-                       bh = bh->b_reqnext;
-               bcount -= count;
-       }
-       pc->bh = bh;
-}
-
 /*
  * called on each failed packet command retry to analyze the request sense. We
  * currently do not utilize this information.
@@ -392,12 +301,10 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense)
                 pc->c[0], tape->sense_key, tape->asc, tape->ascq);
 
        /* Correct pc->xferred by asking the tape.       */
-       if (pc->flags & PC_FLAG_DMA_ERROR) {
+       if (pc->flags & PC_FLAG_DMA_ERROR)
                pc->xferred = pc->req_xfer -
                        tape->blk_size *
                        get_unaligned_be32(&sense[3]);
-               idetape_update_buffers(drive, pc);
-       }
 
        /*
         * If error was the result of a zero-length read or write command,
@@ -436,29 +343,6 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense)
        }
 }
 
-/* Free data buffers completely. */
-static void ide_tape_kfree_buffer(idetape_tape_t *tape)
-{
-       struct idetape_bh *prev_bh, *bh = tape->merge_bh;
-
-       while (bh) {
-               u32 size = bh->b_size;
-
-               while (size) {
-                       unsigned int order = fls(size >> PAGE_SHIFT)-1;
-
-                       if (bh->b_data)
-                               free_pages((unsigned long)bh->b_data, order);
-
-                       size &= (order-1);
-                       bh->b_data += (1 << order) * PAGE_SIZE;
-               }
-               prev_bh = bh;
-               bh = bh->b_reqnext;
-               kfree(prev_bh);
-       }
-}
-
 static void ide_tape_handle_dsc(ide_drive_t *);
 
 static int ide_tape_callback(ide_drive_t *drive, int dsc)
@@ -496,7 +380,7 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc)
                }
 
                tape->first_frame += blocks;
-               rq->current_nr_sectors -= blocks;
+               rq->resid_len -= blocks * tape->blk_size;
 
                if (pc->error) {
                        uptodate = 0;
@@ -558,19 +442,6 @@ static void ide_tape_handle_dsc(ide_drive_t *drive)
        idetape_postpone_request(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)
-               bleft = idetape_output_buffers(drive, pc, bcount);
-       else
-               bleft = idetape_input_buffers(drive, pc, bcount);
-
-       return bcount - bleft;
-}
-
 /*
  * Packet Command Interface
  *
@@ -622,6 +493,8 @@ static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive,
 
        if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
                (pc->flags & PC_FLAG_ABORT)) {
+               unsigned int done = blk_rq_bytes(drive->hwif->rq);
+
                /*
                 * We will "abort" retrying a packet command in case legitimate
                 * error code was received (crossing a filemark, or end of the
@@ -641,8 +514,10 @@ static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive,
                        /* Giving up */
                        pc->error = IDE_DRV_ERROR_GENERAL;
                }
+
                drive->failed_pc = NULL;
                drive->pc_callback(drive, 0);
+               ide_complete_rq(drive, -EIO, done);
                return ide_stopped;
        }
        debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]);
@@ -695,7 +570,7 @@ static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
                                printk(KERN_ERR "ide-tape: %s: I/O error, ",
                                                tape->name);
                        /* Retry operation */
-                       ide_retry_pc(drive, tape->disk);
+                       ide_retry_pc(drive);
                        return ide_stopped;
                }
                pc->error = 0;
@@ -711,27 +586,22 @@ static void ide_tape_create_rw_cmd(idetape_tape_t *tape,
                                   struct ide_atapi_pc *pc, struct request *rq,
                                   u8 opcode)
 {
-       struct idetape_bh *bh = (struct idetape_bh *)rq->special;
-       unsigned int length = rq->current_nr_sectors;
+       unsigned int length = blk_rq_sectors(rq);
 
        ide_init_pc(pc);
        put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
        pc->c[1] = 1;
-       pc->bh = bh;
        pc->buf = NULL;
        pc->buf_size = length * tape->blk_size;
        pc->req_xfer = pc->buf_size;
        if (pc->req_xfer == tape->buffer_size)
                pc->flags |= PC_FLAG_DMA_OK;
 
-       if (opcode == READ_6) {
+       if (opcode == READ_6)
                pc->c[0] = READ_6;
-               atomic_set(&bh->b_count, 0);
-       } else if (opcode == WRITE_6) {
+       else if (opcode == WRITE_6) {
                pc->c[0] = WRITE_6;
                pc->flags |= PC_FLAG_WRITING;
-               pc->b_data = bh->b_data;
-               pc->b_count = atomic_read(&bh->b_count);
        }
 
        memcpy(rq->cmd, pc->c, 12);
@@ -747,12 +617,10 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        struct ide_cmd cmd;
        u8 stat;
 
-       debug_log(DBG_SENSE, "sector: %llu, nr_sectors: %lu,"
-                       " current_nr_sectors: %u\n",
-                       (unsigned long long)rq->sector, rq->nr_sectors,
-                       rq->current_nr_sectors);
+       debug_log(DBG_SENSE, "sector: %llu, nr_sectors: %u\n"
+                 (unsigned long long)blk_rq_pos(rq), blk_rq_sectors(rq));
 
-       if (!blk_special_request(rq)) {
+       if (!(blk_special_request(rq) || blk_sense_request(rq))) {
                /* We do not support buffer cache originated requests. */
                printk(KERN_NOTICE "ide-tape: %s: Unsupported request in "
                        "request queue (%d)\n", drive->name, rq->cmd_type);
@@ -828,7 +696,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                goto out;
        }
        if (rq->cmd[13] & REQ_IDETAPE_PC1) {
-               pc = (struct ide_atapi_pc *) rq->buffer;
+               pc = (struct ide_atapi_pc *)rq->special;
                rq->cmd[13] &= ~(REQ_IDETAPE_PC1);
                rq->cmd[13] |= REQ_IDETAPE_PC2;
                goto out;
@@ -840,6 +708,9 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        BUG();
 
 out:
+       /* prepare sense request for this command */
+       ide_prep_sense(drive, rq);
+
        memset(&cmd, 0, sizeof(cmd));
 
        if (rq_data_dir(rq))
@@ -847,167 +718,10 @@ out:
 
        cmd.rq = rq;
 
-       return ide_tape_issue_pc(drive, &cmd, pc);
-}
-
-/*
- * The function below uses __get_free_pages to allocate a data buffer of size
- * tape->buffer_size (or a bit more). We attempt to combine sequential pages as
- * much as possible.
- *
- * It returns a pointer to the newly allocated buffer, or NULL in case of
- * failure.
- */
-static struct idetape_bh *ide_tape_kmalloc_buffer(idetape_tape_t *tape,
-                                                 int full, int clear)
-{
-       struct idetape_bh *prev_bh, *bh, *merge_bh;
-       int pages = tape->pages_per_buffer;
-       unsigned int order, b_allocd;
-       char *b_data = NULL;
-
-       merge_bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
-       bh = merge_bh;
-       if (bh == NULL)
-               goto abort;
-
-       order = fls(pages) - 1;
-       bh->b_data = (char *) __get_free_pages(GFP_KERNEL, order);
-       if (!bh->b_data)
-               goto abort;
-       b_allocd = (1 << order) * PAGE_SIZE;
-       pages &= (order-1);
-
-       if (clear)
-               memset(bh->b_data, 0, b_allocd);
-       bh->b_reqnext = NULL;
-       bh->b_size = b_allocd;
-       atomic_set(&bh->b_count, full ? bh->b_size : 0);
-
-       while (pages) {
-               order = fls(pages) - 1;
-               b_data = (char *) __get_free_pages(GFP_KERNEL, order);
-               if (!b_data)
-                       goto abort;
-               b_allocd = (1 << order) * PAGE_SIZE;
-
-               if (clear)
-                       memset(b_data, 0, b_allocd);
-
-               /* newly allocated page frames below buffer header or ...*/
-               if (bh->b_data == b_data + b_allocd) {
-                       bh->b_size += b_allocd;
-                       bh->b_data -= b_allocd;
-                       if (full)
-                               atomic_add(b_allocd, &bh->b_count);
-                       continue;
-               }
-               /* they are above the header */
-               if (b_data == bh->b_data + bh->b_size) {
-                       bh->b_size += b_allocd;
-                       if (full)
-                               atomic_add(b_allocd, &bh->b_count);
-                       continue;
-               }
-               prev_bh = bh;
-               bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
-               if (!bh) {
-                       free_pages((unsigned long) b_data, order);
-                       goto abort;
-               }
-               bh->b_reqnext = NULL;
-               bh->b_data = b_data;
-               bh->b_size = b_allocd;
-               atomic_set(&bh->b_count, full ? bh->b_size : 0);
-               prev_bh->b_reqnext = bh;
-
-               pages &= (order-1);
-       }
-
-       bh->b_size -= tape->excess_bh_size;
-       if (full)
-               atomic_sub(tape->excess_bh_size, &bh->b_count);
-       return merge_bh;
-abort:
-       ide_tape_kfree_buffer(tape);
-       return NULL;
-}
+       ide_init_sg_cmd(&cmd, pc->req_xfer);
+       ide_map_sg(drive, &cmd);
 
-static int idetape_copy_stage_from_user(idetape_tape_t *tape,
-                                       const char __user *buf, int n)
-{
-       struct idetape_bh *bh = tape->bh;
-       int count;
-       int ret = 0;
-
-       while (n) {
-               if (bh == NULL) {
-                       printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
-                                       __func__);
-                       return 1;
-               }
-               count = min((unsigned int)
-                               (bh->b_size - atomic_read(&bh->b_count)),
-                               (unsigned int)n);
-               if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf,
-                               count))
-                       ret = 1;
-               n -= count;
-               atomic_add(count, &bh->b_count);
-               buf += count;
-               if (atomic_read(&bh->b_count) == bh->b_size) {
-                       bh = bh->b_reqnext;
-                       if (bh)
-                               atomic_set(&bh->b_count, 0);
-               }
-       }
-       tape->bh = bh;
-       return ret;
-}
-
-static int idetape_copy_stage_to_user(idetape_tape_t *tape, char __user *buf,
-                                     int n)
-{
-       struct idetape_bh *bh = tape->bh;
-       int count;
-       int ret = 0;
-
-       while (n) {
-               if (bh == NULL) {
-                       printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
-                                       __func__);
-                       return 1;
-               }
-               count = min(tape->b_count, n);
-               if  (copy_to_user(buf, tape->b_data, count))
-                       ret = 1;
-               n -= count;
-               tape->b_data += count;
-               tape->b_count -= count;
-               buf += count;
-               if (!tape->b_count) {
-                       bh = bh->b_reqnext;
-                       tape->bh = bh;
-                       if (bh) {
-                               tape->b_data = bh->b_data;
-                               tape->b_count = atomic_read(&bh->b_count);
-                       }
-               }
-       }
-       return ret;
-}
-
-static void idetape_init_merge_buffer(idetape_tape_t *tape)
-{
-       struct idetape_bh *bh = tape->merge_bh;
-       tape->bh = tape->merge_bh;
-
-       if (tape->chrdev_dir == IDETAPE_DIR_WRITE)
-               atomic_set(&bh->b_count, 0);
-       else {
-               tape->b_data = bh->b_data;
-               tape->b_count = atomic_read(&bh->b_count);
-       }
+       return ide_tape_issue_pc(drive, &cmd, pc);
 }
 
 /*
@@ -1107,10 +821,10 @@ static void __ide_tape_discard_merge_buffer(ide_drive_t *drive)
                return;
 
        clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags);
-       tape->merge_bh_size = 0;
-       if (tape->merge_bh != NULL) {
-               ide_tape_kfree_buffer(tape);
-               tape->merge_bh = NULL;
+       tape->valid = 0;
+       if (tape->buf != NULL) {
+               kfree(tape->buf);
+               tape->buf = NULL;
        }
 
        tape->chrdev_dir = IDETAPE_DIR_NONE;
@@ -1164,36 +878,44 @@ static void ide_tape_discard_merge_buffer(ide_drive_t *drive,
  * Generate a read/write request for the block device interface and wait for it
  * to be serviced.
  */
-static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks,
-                                struct idetape_bh *bh)
+static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size)
 {
        idetape_tape_t *tape = drive->driver_data;
        struct request *rq;
-       int ret, errors;
+       int ret;
 
        debug_log(DBG_SENSE, "%s: cmd=%d\n", __func__, cmd);
+       BUG_ON(cmd != REQ_IDETAPE_READ && cmd != REQ_IDETAPE_WRITE);
+       BUG_ON(size < 0 || size % tape->blk_size);
 
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
        rq->cmd_type = REQ_TYPE_SPECIAL;
        rq->cmd[13] = cmd;
        rq->rq_disk = tape->disk;
-       rq->special = (void *)bh;
-       rq->sector = tape->first_frame;
-       rq->nr_sectors = blocks;
-       rq->current_nr_sectors = blocks;
-       blk_execute_rq(drive->queue, tape->disk, rq, 0);
+       rq->__sector = tape->first_frame;
 
-       errors = rq->errors;
-       ret = tape->blk_size * (blocks - rq->current_nr_sectors);
-       blk_put_request(rq);
+       if (size) {
+               ret = blk_rq_map_kern(drive->queue, rq, tape->buf, size,
+                                     __GFP_WAIT);
+               if (ret)
+                       goto out_put;
+       }
 
-       if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0)
-               return 0;
+       blk_execute_rq(drive->queue, tape->disk, rq, 0);
 
-       if (tape->merge_bh)
-               idetape_init_merge_buffer(tape);
-       if (errors == IDE_DRV_ERROR_GENERAL)
-               return -EIO;
+       /* calculate the number of transferred bytes and update buffer state */
+       size -= rq->resid_len;
+       tape->cur = tape->buf;
+       if (cmd == REQ_IDETAPE_READ)
+               tape->valid = size;
+       else
+               tape->valid = 0;
+
+       ret = size;
+       if (rq->errors == IDE_DRV_ERROR_GENERAL)
+               ret = -EIO;
+out_put:
+       blk_put_request(rq);
        return ret;
 }
 
@@ -1230,153 +952,87 @@ static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd)
        pc->flags |= PC_FLAG_WAIT_FOR_DSC;
 }
 
-/* Queue up a character device originated write request. */
-static int idetape_add_chrdev_write_request(ide_drive_t *drive, int blocks)
-{
-       idetape_tape_t *tape = drive->driver_data;
-
-       debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
-
-       return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE,
-                                    blocks, tape->merge_bh);
-}
-
 static void ide_tape_flush_merge_buffer(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
-       int blocks, min;
-       struct idetape_bh *bh;
 
        if (tape->chrdev_dir != IDETAPE_DIR_WRITE) {
                printk(KERN_ERR "ide-tape: bug: Trying to empty merge buffer"
                                " but we are not writing.\n");
                return;
        }
-       if (tape->merge_bh_size > tape->buffer_size) {
-               printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n");
-               tape->merge_bh_size = tape->buffer_size;
-       }
-       if (tape->merge_bh_size) {
-               blocks = tape->merge_bh_size / tape->blk_size;
-               if (tape->merge_bh_size % tape->blk_size) {
-                       unsigned int i;
-
-                       blocks++;
-                       i = tape->blk_size - tape->merge_bh_size %
-                               tape->blk_size;
-                       bh = tape->bh->b_reqnext;
-                       while (bh) {
-                               atomic_set(&bh->b_count, 0);
-                               bh = bh->b_reqnext;
-                       }
-                       bh = tape->bh;
-                       while (i) {
-                               if (bh == NULL) {
-                                       printk(KERN_INFO "ide-tape: bug,"
-                                                        " bh NULL\n");
-                                       break;
-                               }
-                               min = min(i, (unsigned int)(bh->b_size -
-                                               atomic_read(&bh->b_count)));
-                               memset(bh->b_data + atomic_read(&bh->b_count),
-                                               0, min);
-                               atomic_add(min, &bh->b_count);
-                               i -= min;
-                               bh = bh->b_reqnext;
-                       }
-               }
-               (void) idetape_add_chrdev_write_request(drive, blocks);
-               tape->merge_bh_size = 0;
-       }
-       if (tape->merge_bh != NULL) {
-               ide_tape_kfree_buffer(tape);
-               tape->merge_bh = NULL;
+       if (tape->buf) {
+               size_t aligned = roundup(tape->valid, tape->blk_size);
+
+               memset(tape->cur, 0, aligned - tape->valid);
+               idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, aligned);
+               kfree(tape->buf);
+               tape->buf = NULL;
        }
        tape->chrdev_dir = IDETAPE_DIR_NONE;
 }
 
-static int idetape_init_read(ide_drive_t *drive)
+static int idetape_init_rw(ide_drive_t *drive, int dir)
 {
        idetape_tape_t *tape = drive->driver_data;
-       int bytes_read;
+       int rc;
 
-       /* Initialize read operation */
-       if (tape->chrdev_dir != IDETAPE_DIR_READ) {
-               if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
-                       ide_tape_flush_merge_buffer(drive);
-                       idetape_flush_tape_buffers(drive);
-               }
-               if (tape->merge_bh || tape->merge_bh_size) {
-                       printk(KERN_ERR "ide-tape: merge_bh_size should be"
-                                        " 0 now\n");
-                       tape->merge_bh_size = 0;
-               }
-               tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0, 0);
-               if (!tape->merge_bh)
-                       return -ENOMEM;
-               tape->chrdev_dir = IDETAPE_DIR_READ;
+       BUG_ON(dir != IDETAPE_DIR_READ && dir != IDETAPE_DIR_WRITE);
 
-               /*
-                * Issue a read 0 command to ensure that DSC handshake is
-                * switched from completion mode to buffer available mode.
-                * No point in issuing this if DSC overlap isn't supported, some
-                * drives (Seagate STT3401A) will return an error.
-                */
-               if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) {
-                       bytes_read = idetape_queue_rw_tail(drive,
-                                                       REQ_IDETAPE_READ, 0,
-                                                       tape->merge_bh);
-                       if (bytes_read < 0) {
-                               ide_tape_kfree_buffer(tape);
-                               tape->merge_bh = NULL;
-                               tape->chrdev_dir = IDETAPE_DIR_NONE;
-                               return bytes_read;
-                       }
-               }
-       }
+       if (tape->chrdev_dir == dir)
+               return 0;
 
-       return 0;
-}
+       if (tape->chrdev_dir == IDETAPE_DIR_READ)
+               ide_tape_discard_merge_buffer(drive, 1);
+       else if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
+               ide_tape_flush_merge_buffer(drive);
+               idetape_flush_tape_buffers(drive);
+       }
 
-/* called from idetape_chrdev_read() to service a chrdev read request. */
-static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks)
-{
-       idetape_tape_t *tape = drive->driver_data;
+       if (tape->buf || tape->valid) {
+               printk(KERN_ERR "ide-tape: valid should be 0 now\n");
+               tape->valid = 0;
+       }
 
-       debug_log(DBG_PROCS, "Enter %s, %d blocks\n", __func__, blocks);
+       tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL);
+       if (!tape->buf)
+               return -ENOMEM;
+       tape->chrdev_dir = dir;
+       tape->cur = tape->buf;
 
-       /* If we are at a filemark, return a read length of 0 */
-       if (test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags))
-               return 0;
-
-       idetape_init_read(drive);
+       /*
+        * Issue a 0 rw command to ensure that DSC handshake is
+        * switched from completion mode to buffer available mode.  No
+        * point in issuing this if DSC overlap isn't supported, some
+        * drives (Seagate STT3401A) will return an error.
+        */
+       if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) {
+               int cmd = dir == IDETAPE_DIR_READ ? REQ_IDETAPE_READ
+                                                 : REQ_IDETAPE_WRITE;
+
+               rc = idetape_queue_rw_tail(drive, cmd, 0);
+               if (rc < 0) {
+                       kfree(tape->buf);
+                       tape->buf = NULL;
+                       tape->chrdev_dir = IDETAPE_DIR_NONE;
+                       return rc;
+               }
+       }
 
-       return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks,
-                                    tape->merge_bh);
+       return 0;
 }
 
 static void idetape_pad_zeros(ide_drive_t *drive, int bcount)
 {
        idetape_tape_t *tape = drive->driver_data;
-       struct idetape_bh *bh;
-       int blocks;
+
+       memset(tape->buf, 0, tape->buffer_size);
 
        while (bcount) {
-               unsigned int count;
+               unsigned int count = min(tape->buffer_size, bcount);
 
-               bh = tape->merge_bh;
-               count = min(tape->buffer_size, bcount);
+               idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, count);
                bcount -= count;
-               blocks = count / tape->blk_size;
-               while (count) {
-                       atomic_set(&bh->b_count,
-                                  min(count, (unsigned int)bh->b_size));
-                       memset(bh->b_data, 0, atomic_read(&bh->b_count));
-                       count -= atomic_read(&bh->b_count);
-                       bh = bh->b_reqnext;
-               }
-               idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks,
-                                     tape->merge_bh);
        }
 }
 
@@ -1456,7 +1112,7 @@ static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
        }
 
        if (tape->chrdev_dir == IDETAPE_DIR_READ) {
-               tape->merge_bh_size = 0;
+               tape->valid = 0;
                if (test_and_clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags))
                        ++count;
                ide_tape_discard_merge_buffer(drive, 0);
@@ -1505,9 +1161,9 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
 {
        struct ide_tape_obj *tape = file->private_data;
        ide_drive_t *drive = tape->drive;
-       ssize_t bytes_read, temp, actually_read = 0, rc;
+       size_t done = 0;
        ssize_t ret = 0;
-       u16 ctl = *(u16 *)&tape->caps[12];
+       int rc;
 
        debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
 
@@ -1517,49 +1173,43 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
                            (count % tape->blk_size) == 0)
                                tape->user_bs_factor = count / tape->blk_size;
        }
-       rc = idetape_init_read(drive);
+
+       rc = idetape_init_rw(drive, IDETAPE_DIR_READ);
        if (rc < 0)
                return rc;
-       if (count == 0)
-               return (0);
-       if (tape->merge_bh_size) {
-               actually_read = min((unsigned int)(tape->merge_bh_size),
-                                   (unsigned int)count);
-               if (idetape_copy_stage_to_user(tape, buf, actually_read))
-                       ret = -EFAULT;
-               buf += actually_read;
-               tape->merge_bh_size -= actually_read;
-               count -= actually_read;
-       }
-       while (count >= tape->buffer_size) {
-               bytes_read = idetape_add_chrdev_read_request(drive, ctl);
-               if (bytes_read <= 0)
-                       goto finish;
-               if (idetape_copy_stage_to_user(tape, buf, bytes_read))
-                       ret = -EFAULT;
-               buf += bytes_read;
-               count -= bytes_read;
-               actually_read += bytes_read;
-       }
-       if (count) {
-               bytes_read = idetape_add_chrdev_read_request(drive, ctl);
-               if (bytes_read <= 0)
-                       goto finish;
-               temp = min((unsigned long)count, (unsigned long)bytes_read);
-               if (idetape_copy_stage_to_user(tape, buf, temp))
+
+       while (done < count) {
+               size_t todo;
+
+               /* refill if staging buffer is empty */
+               if (!tape->valid) {
+                       /* If we are at a filemark, nothing more to read */
+                       if (test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags))
+                               break;
+                       /* read */
+                       if (idetape_queue_rw_tail(drive, REQ_IDETAPE_READ,
+                                                 tape->buffer_size) <= 0)
+                               break;
+               }
+
+               /* copy out */
+               todo = min_t(size_t, count - done, tape->valid);
+               if (copy_to_user(buf + done, tape->cur, todo))
                        ret = -EFAULT;
-               actually_read += temp;
-               tape->merge_bh_size = bytes_read-temp;
+
+               tape->cur += todo;
+               tape->valid -= todo;
+               done += todo;
        }
-finish:
-       if (!actually_read && test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) {
+
+       if (!done && test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) {
                debug_log(DBG_SENSE, "%s: spacing over filemark\n", tape->name);
 
                idetape_space_over_filemarks(drive, MTFSF, 1);
                return 0;
        }
 
-       return ret ? ret : actually_read;
+       return ret ? ret : done;
 }
 
 static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
@@ -1567,9 +1217,9 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
 {
        struct ide_tape_obj *tape = file->private_data;
        ide_drive_t *drive = tape->drive;
-       ssize_t actually_written = 0;
+       size_t done = 0;
        ssize_t ret = 0;
-       u16 ctl = *(u16 *)&tape->caps[12];
+       int rc;
 
        /* The drive is write protected. */
        if (tape->write_prot)
@@ -1578,80 +1228,31 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
        debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
 
        /* Initialize write operation */
-       if (tape->chrdev_dir != IDETAPE_DIR_WRITE) {
-               if (tape->chrdev_dir == IDETAPE_DIR_READ)
-                       ide_tape_discard_merge_buffer(drive, 1);
-               if (tape->merge_bh || tape->merge_bh_size) {
-                       printk(KERN_ERR "ide-tape: merge_bh_size "
-                               "should be 0 now\n");
-                       tape->merge_bh_size = 0;
-               }
-               tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0, 0);
-               if (!tape->merge_bh)
-                       return -ENOMEM;
-               tape->chrdev_dir = IDETAPE_DIR_WRITE;
-               idetape_init_merge_buffer(tape);
+       rc = idetape_init_rw(drive, IDETAPE_DIR_WRITE);
+       if (rc < 0)
+               return rc;
 
-               /*
-                * Issue a write 0 command to ensure that DSC handshake is
-                * switched from completion mode to buffer available mode. No
-                * point in issuing this if DSC overlap isn't supported, some
-                * drives (Seagate STT3401A) will return an error.
-                */
-               if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) {
-                       ssize_t retval = idetape_queue_rw_tail(drive,
-                                                       REQ_IDETAPE_WRITE, 0,
-                                                       tape->merge_bh);
-                       if (retval < 0) {
-                               ide_tape_kfree_buffer(tape);
-                               tape->merge_bh = NULL;
-                               tape->chrdev_dir = IDETAPE_DIR_NONE;
-                               return retval;
-                       }
-               }
-       }
-       if (count == 0)
-               return (0);
-       if (tape->merge_bh_size) {
-               if (tape->merge_bh_size >= tape->buffer_size) {
-                       printk(KERN_ERR "ide-tape: bug: merge buf too big\n");
-                       tape->merge_bh_size = 0;
-               }
-               actually_written = min((unsigned int)
-                               (tape->buffer_size - tape->merge_bh_size),
-                               (unsigned int)count);
-               if (idetape_copy_stage_from_user(tape, buf, actually_written))
-                               ret = -EFAULT;
-               buf += actually_written;
-               tape->merge_bh_size += actually_written;
-               count -= actually_written;
-
-               if (tape->merge_bh_size == tape->buffer_size) {
-                       ssize_t retval;
-                       tape->merge_bh_size = 0;
-                       retval = idetape_add_chrdev_write_request(drive, ctl);
-                       if (retval <= 0)
-                               return (retval);
-               }
-       }
-       while (count >= tape->buffer_size) {
-               ssize_t retval;
-               if (idetape_copy_stage_from_user(tape, buf, tape->buffer_size))
-                       ret = -EFAULT;
-               buf += tape->buffer_size;
-               count -= tape->buffer_size;
-               retval = idetape_add_chrdev_write_request(drive, ctl);
-               actually_written += tape->buffer_size;
-               if (retval <= 0)
-                       return (retval);
-       }
-       if (count) {
-               actually_written += count;
-               if (idetape_copy_stage_from_user(tape, buf, count))
+       while (done < count) {
+               size_t todo;
+
+               /* flush if staging buffer is full */
+               if (tape->valid == tape->buffer_size &&
+                   idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE,
+                                         tape->buffer_size) <= 0)
+                       return rc;
+
+               /* copy in */
+               todo = min_t(size_t, count - done,
+                            tape->buffer_size - tape->valid);
+               if (copy_from_user(tape->cur, buf + done, todo))
                        ret = -EFAULT;
-               tape->merge_bh_size += count;
+
+               tape->cur += todo;
+               tape->valid += todo;
+               done += todo;
        }
-       return ret ? ret : actually_written;
+
+       return ret ? ret : done;
 }
 
 static int idetape_write_filemark(ide_drive_t *drive)
@@ -1812,7 +1413,7 @@ static int idetape_chrdev_ioctl(struct inode *inode, struct file *file,
                idetape_flush_tape_buffers(drive);
        }
        if (cmd == MTIOCGET || cmd == MTIOCPOS) {
-               block_offset = tape->merge_bh_size /
+               block_offset = tape->valid /
                        (tape->blk_size * tape->user_bs_factor);
                position = idetape_read_position(drive);
                if (position < 0)
@@ -1960,12 +1561,12 @@ static void idetape_write_release(ide_drive_t *drive, unsigned int minor)
        idetape_tape_t *tape = drive->driver_data;
 
        ide_tape_flush_merge_buffer(drive);
-       tape->merge_bh = ide_tape_kmalloc_buffer(tape, 1, 0);
-       if (tape->merge_bh != NULL) {
+       tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL);
+       if (tape->buf != NULL) {
                idetape_pad_zeros(drive, tape->blk_size *
                                (tape->user_bs_factor - 1));
-               ide_tape_kfree_buffer(tape);
-               tape->merge_bh = NULL;
+               kfree(tape->buf);
+               tape->buf = NULL;
        }
        idetape_write_filemark(drive);
        idetape_flush_tape_buffers(drive);
@@ -2159,8 +1760,6 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
        u16 *ctl = (u16 *)&tape->caps[12];
 
        drive->pc_callback       = ide_tape_callback;
-       drive->pc_update_buffers = idetape_update_buffers;
-       drive->pc_io_buffers     = ide_tape_io_buffers;
 
        drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
 
@@ -2191,11 +1790,6 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
                tape->buffer_size = *ctl * tape->blk_size;
        }
        buffer_size = tape->buffer_size;
-       tape->pages_per_buffer = buffer_size / PAGE_SIZE;
-       if (buffer_size % PAGE_SIZE) {
-               tape->pages_per_buffer++;
-               tape->excess_bh_size = PAGE_SIZE - buffer_size % PAGE_SIZE;
-       }
 
        /* select the "best" DSC read/write polling freq */
        speed = max(*(u16 *)&tape->caps[14], *(u16 *)&tape->caps[8]);
@@ -2238,7 +1832,7 @@ static void ide_tape_release(struct device *dev)
        ide_drive_t *drive = tape->drive;
        struct gendisk *g = tape->disk;
 
-       BUG_ON(tape->merge_bh_size);
+       BUG_ON(tape->valid);
 
        drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
        drive->driver_data = NULL;
index 4aa6223c11bea0ee138fec32dfd29fbf7facd30e..a0c3e1b2f73c20b6b005eb9ce2b35ea61bbb42f1 100644 (file)
@@ -385,7 +385,7 @@ out_end:
        if ((cmd->tf_flags & IDE_TFLAG_FS) == 0)
                ide_finish_cmd(drive, cmd, stat);
        else
-               ide_complete_rq(drive, 0, cmd->rq->nr_sectors << 9);
+               ide_complete_rq(drive, 0, blk_rq_sectors(cmd->rq) << 9);
        return ide_stopped;
 out_err:
        ide_error_cmd(drive, cmd);
@@ -424,7 +424,9 @@ int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf,
 
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
        rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
-       rq->buffer = buf;
+
+       if (cmd->tf_flags & IDE_TFLAG_WRITE)
+               rq->cmd_flags |= REQ_RW;
 
        /*
         * (ks) We transfer currently only whole sectors.
@@ -432,18 +434,20 @@ int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf,
         * if we would find a solution to transfer any size.
         * To support special commands like READ LONG.
         */
-       rq->hard_nr_sectors = rq->nr_sectors = nsect;
-       rq->hard_cur_sectors = rq->current_nr_sectors = nsect;
-
-       if (cmd->tf_flags & IDE_TFLAG_WRITE)
-               rq->cmd_flags |= REQ_RW;
+       if (nsect) {
+               error = blk_rq_map_kern(drive->queue, rq, buf,
+                                       nsect * SECTOR_SIZE, __GFP_WAIT);
+               if (error)
+                       goto put_req;
+       }
 
        rq->special = cmd;
        cmd->rq = rq;
 
        error = blk_execute_rq(drive->queue, NULL, rq, 0);
-       blk_put_request(rq);
 
+put_req:
+       blk_put_request(rq);
        return error;
 }
 
index b3bc96f930a6feb227d2827ef8ee748a29e2030c..e24ecc87a9b1837a60bdfce7ae59fffd1b2ad7f1 100644 (file)
@@ -177,7 +177,7 @@ static void pdc202xx_dma_start(ide_drive_t *drive)
                u8 clock = inb(high_16 + 0x11);
 
                outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
-               word_count = (rq->nr_sectors << 8);
+               word_count = (blk_rq_sectors(rq) << 8);
                word_count = (rq_data_dir(rq) == READ) ?
                                        word_count | 0x05000000 :
                                        word_count | 0x06000000;
index b4cf42dc8a6fcf4cd155ae0bd3f7ad9868a10106..05a93d6baecc60edf3ba587ab26c0947907915aa 100644 (file)
@@ -112,7 +112,7 @@ static void tc86c001_dma_start(ide_drive_t *drive)
        ide_hwif_t *hwif        = drive->hwif;
        unsigned long sc_base   = hwif->config_data;
        unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
-       unsigned long nsectors  = hwif->rq->nr_sectors;
+       unsigned long nsectors  = blk_rq_sectors(hwif->rq);
 
        /*
         * We have to manually load the sector count and size into
index 564422d239766a97debc65ff45546d0bbfa9095b..5ca76224f6d11a731b585f98a35ea8e2661c4e5e 100644 (file)
@@ -307,7 +307,7 @@ static int tx4939ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
        tx4939ide_writew(SECTOR_SIZE / 2, base, drive->dn ?
                         TX4939IDE_Xfer_Cnt_2 : TX4939IDE_Xfer_Cnt_1);
 
-       tx4939ide_writew(cmd->rq->nr_sectors, base, TX4939IDE_Sec_Cnt);
+       tx4939ide_writew(blk_rq_sectors(cmd->rq), base, TX4939IDE_Sec_Cnt);
 
        return 0;
 }
index 56df1cee8fb3435a43e33b07ba1a3dadaf528680..3319c2fec28e40f7908d7e0688595c113f3a597f 100644 (file)
@@ -232,7 +232,7 @@ static struct page *read_sb_page(mddev_t *mddev, long offset,
                target = rdev->sb_start + offset + index * (PAGE_SIZE/512);
 
                if (sync_page_io(rdev->bdev, target,
-                                roundup(size, bdev_hardsect_size(rdev->bdev)),
+                                roundup(size, bdev_logical_block_size(rdev->bdev)),
                                 page, READ)) {
                        page->index = index;
                        attach_page_buffers(page, NULL); /* so that free_buffer will
@@ -287,7 +287,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
                        int size = PAGE_SIZE;
                        if (page->index == bitmap->file_pages-1)
                                size = roundup(bitmap->last_page_size,
-                                              bdev_hardsect_size(rdev->bdev));
+                                              bdev_logical_block_size(rdev->bdev));
                        /* Just make sure we aren't corrupting data or
                         * metadata
                         */
index a2e26c24214150cac23e92acf1391a212d60271b..75d8081a904175bcff7d3199c2deba4140fc6086 100644 (file)
@@ -178,7 +178,7 @@ static int set_chunk_size(struct dm_exception_store *store,
        }
 
        /* Validate the chunk size against the device block size */
-       if (chunk_size_ulong % (bdev_hardsect_size(store->cow->bdev) >> 9)) {
+       if (chunk_size_ulong % (bdev_logical_block_size(store->cow->bdev) >> 9)) {
                *error = "Chunk size is not a multiple of device blocksize";
                return -EINVAL;
        }
index be233bc4d91787a2729ef8ca740a946ddc782332..6fa8ccf91c70e70174d578e10b8793b884a86406 100644 (file)
@@ -413,7 +413,8 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
                 * Buffer holds both header and bitset.
                 */
                buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) +
-                                      bitset_size, ti->limits.hardsect_size);
+                                      bitset_size,
+                                      ti->limits.logical_block_size);
 
                if (buf_size > dev->bdev->bd_inode->i_size) {
                        DMWARN("log device %s too small: need %llu bytes",
index e75c6dd76a9adfb3b374aa9cc6d48a2db14596be..2662a41337e7813b370df2d61dbfc70e964e066a 100644 (file)
@@ -282,7 +282,7 @@ static int read_header(struct pstore *ps, int *new_snapshot)
         */
        if (!ps->store->chunk_size) {
                ps->store->chunk_size = max(DM_CHUNK_SIZE_DEFAULT_SECTORS,
-                   bdev_hardsect_size(ps->store->cow->bdev) >> 9);
+                   bdev_logical_block_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;
index 429b50b975d5a14af8c8e97412425ae9169784d3..e9a73bb242b0935eefae2ce0744ed97965a2143d 100644 (file)
@@ -108,7 +108,8 @@ static void combine_restrictions_low(struct io_restrictions *lhs,
        lhs->max_hw_segments =
                min_not_zero(lhs->max_hw_segments, rhs->max_hw_segments);
 
-       lhs->hardsect_size = max(lhs->hardsect_size, rhs->hardsect_size);
+       lhs->logical_block_size = max(lhs->logical_block_size,
+                                     rhs->logical_block_size);
 
        lhs->max_segment_size =
                min_not_zero(lhs->max_segment_size, rhs->max_segment_size);
@@ -509,7 +510,7 @@ void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev)
         *        combine_restrictions_low()
         */
        rs->max_sectors =
-               min_not_zero(rs->max_sectors, q->max_sectors);
+               min_not_zero(rs->max_sectors, queue_max_sectors(q));
 
        /*
         * Check if merge fn is supported.
@@ -524,24 +525,25 @@ void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev)
 
        rs->max_phys_segments =
                min_not_zero(rs->max_phys_segments,
-                            q->max_phys_segments);
+                            queue_max_phys_segments(q));
 
        rs->max_hw_segments =
-               min_not_zero(rs->max_hw_segments, q->max_hw_segments);
+               min_not_zero(rs->max_hw_segments, queue_max_hw_segments(q));
 
-       rs->hardsect_size = max(rs->hardsect_size, q->hardsect_size);
+       rs->logical_block_size = max(rs->logical_block_size,
+                                    queue_logical_block_size(q));
 
        rs->max_segment_size =
-               min_not_zero(rs->max_segment_size, q->max_segment_size);
+               min_not_zero(rs->max_segment_size, queue_max_segment_size(q));
 
        rs->max_hw_sectors =
-               min_not_zero(rs->max_hw_sectors, q->max_hw_sectors);
+               min_not_zero(rs->max_hw_sectors, queue_max_hw_sectors(q));
 
        rs->seg_boundary_mask =
                min_not_zero(rs->seg_boundary_mask,
-                            q->seg_boundary_mask);
+                            queue_segment_boundary(q));
 
-       rs->bounce_pfn = min_not_zero(rs->bounce_pfn, q->bounce_pfn);
+       rs->bounce_pfn = min_not_zero(rs->bounce_pfn, queue_bounce_pfn(q));
 
        rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
 }
@@ -683,8 +685,8 @@ static void check_for_valid_limits(struct io_restrictions *rs)
                rs->max_phys_segments = MAX_PHYS_SEGMENTS;
        if (!rs->max_hw_segments)
                rs->max_hw_segments = MAX_HW_SEGMENTS;
-       if (!rs->hardsect_size)
-               rs->hardsect_size = 1 << SECTOR_SHIFT;
+       if (!rs->logical_block_size)
+               rs->logical_block_size = 1 << SECTOR_SHIFT;
        if (!rs->max_segment_size)
                rs->max_segment_size = MAX_SEGMENT_SIZE;
        if (!rs->seg_boundary_mask)
@@ -912,13 +914,13 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q)
         * restrictions.
         */
        blk_queue_max_sectors(q, t->limits.max_sectors);
-       q->max_phys_segments = t->limits.max_phys_segments;
-       q->max_hw_segments = t->limits.max_hw_segments;
-       q->hardsect_size = t->limits.hardsect_size;
-       q->max_segment_size = t->limits.max_segment_size;
-       q->max_hw_sectors = t->limits.max_hw_sectors;
-       q->seg_boundary_mask = t->limits.seg_boundary_mask;
-       q->bounce_pfn = t->limits.bounce_pfn;
+       blk_queue_max_phys_segments(q, t->limits.max_phys_segments);
+       blk_queue_max_hw_segments(q, t->limits.max_hw_segments);
+       blk_queue_logical_block_size(q, t->limits.logical_block_size);
+       blk_queue_max_segment_size(q, t->limits.max_segment_size);
+       blk_queue_max_hw_sectors(q, t->limits.max_hw_sectors);
+       blk_queue_segment_boundary(q, t->limits.seg_boundary_mask);
+       blk_queue_bounce_limit(q, t->limits.bounce_pfn);
 
        if (t->limits.no_cluster)
                queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q);
index 424f7b048c304e8f2a4c7da7e325abbbd1859b53..3fd8b1e65483da53070f0fe633e82843ac1a5ba0 100644 (file)
@@ -20,7 +20,8 @@
 #include <linux/idr.h>
 #include <linux/hdreg.h>
 #include <linux/blktrace_api.h>
-#include <trace/block.h>
+
+#include <trace/events/block.h>
 
 #define DM_MSG_PREFIX "core"
 
@@ -53,8 +54,6 @@ struct dm_target_io {
        union map_info info;
 };
 
-DEFINE_TRACE(block_bio_complete);
-
 /*
  * For request-based dm.
  * One of these is allocated per request.
@@ -656,8 +655,7 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
                /* the bio has been remapped so dispatch it */
 
                trace_block_remap(bdev_get_queue(clone->bi_bdev), clone,
-                                   tio->io->bio->bi_bdev->bd_dev,
-                                   clone->bi_sector, sector);
+                                   tio->io->bio->bi_bdev->bd_dev, sector);
 
                generic_make_request(clone);
        } else if (r < 0 || r == DM_MAPIO_REQUEUE) {
index 7a36e38393a1e9ff24defd03c756138a9f5da903..64f1f3e046e088dc925e00881583484c5e7bc2cd 100644 (file)
@@ -146,7 +146,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
                 * a one page request is never in violation.
                 */
                if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
-                   mddev->queue->max_sectors > (PAGE_SIZE>>9))
+                   queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
                        blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
                disk->num_sectors = rdev->sectors;
index 641b211fe3feb33e15cb1159e3a76ca26b90c124..20f6ac3383490c2a6d31c345226caddd3c578b21 100644 (file)
@@ -1202,7 +1202,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
        atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read));
 
        rdev->sb_size = le32_to_cpu(sb->max_dev) * 2 + 256;
-       bmask = queue_hardsect_size(rdev->bdev->bd_disk->queue)-1;
+       bmask = queue_logical_block_size(rdev->bdev->bd_disk->queue)-1;
        if (rdev->sb_size & bmask)
                rdev->sb_size = (rdev->sb_size | bmask) + 1;
 
index 41ced0cbe823c7275cc2f79172cc9913385fcd2f..4ee31aa13c4073faa2bbfb44f85cb9afd3c96624 100644 (file)
@@ -303,7 +303,7 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
                 * merge_bvec_fn will be involved in multipath.)
                 */
                        if (q->merge_bvec_fn &&
-                           mddev->queue->max_sectors > (PAGE_SIZE>>9))
+                           queue_max_sectors(q) > (PAGE_SIZE>>9))
                                blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
                        conf->working_disks++;
@@ -467,7 +467,7 @@ static int multipath_run (mddev_t *mddev)
                 * violating it, not that we ever expect a device with
                 * a merge_bvec_fn to be involved in multipath */
                if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
-                   mddev->queue->max_sectors > (PAGE_SIZE>>9))
+                   queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
                        blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
                if (!test_bit(Faulty, &rdev->flags))
index c08d7559be5531fb01bedb55e4663a0e40092607..925507e7d673babb32585684916976ad01d04025 100644 (file)
@@ -144,7 +144,7 @@ static int create_strip_zones (mddev_t *mddev)
                 */
 
                if (rdev1->bdev->bd_disk->queue->merge_bvec_fn &&
-                   mddev->queue->max_sectors > (PAGE_SIZE>>9))
+                   queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
                        blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
                if (!smallest || (rdev1->sectors < smallest->sectors))
index 36df9109cde18bb33aec2992afbfb00b1309b587..e23758b4a34e2b65c157be93903d8f416cba7cec 100644 (file)
@@ -1130,7 +1130,7 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
                         * a one page request is never in violation.
                         */
                        if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
-                           mddev->queue->max_sectors > (PAGE_SIZE>>9))
+                           queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
                                blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
                        p->head_position = 0;
@@ -1996,7 +1996,7 @@ static int run(mddev_t *mddev)
                 * a one page request is never in violation.
                 */
                if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
-                   mddev->queue->max_sectors > (PAGE_SIZE>>9))
+                   queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
                        blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
                disk->head_position = 0;
index 499620afb44b259184d3a04ba73fb5a1e7d2c724..750550c1166fe4725efec1935d38d7eaeb4779a4 100644 (file)
@@ -1158,8 +1158,8 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
                         * a one page request is never in violation.
                         */
                        if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
-                           mddev->queue->max_sectors > (PAGE_SIZE>>9))
-                               mddev->queue->max_sectors = (PAGE_SIZE>>9);
+                           queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
+                               blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
                        p->head_position = 0;
                        rdev->raid_disk = mirror;
@@ -2145,8 +2145,8 @@ static int run(mddev_t *mddev)
                 * a one page request is never in violation.
                 */
                if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
-                   mddev->queue->max_sectors > (PAGE_SIZE>>9))
-                       mddev->queue->max_sectors = (PAGE_SIZE>>9);
+                   queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
+                       blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
                disk->head_position = 0;
        }
index bb37fb1b2d82dd484e749ec3b18a9dcf9e1b8f55..bef8766982321f0032f2a62d171f7dcf5baf2b27 100644 (file)
@@ -3463,10 +3463,10 @@ static int bio_fits_rdev(struct bio *bi)
 {
        struct request_queue *q = bdev_get_queue(bi->bi_bdev);
 
-       if ((bi->bi_size>>9) > q->max_sectors)
+       if ((bi->bi_size>>9) > queue_max_sectors(q))
                return 0;
        blk_recount_segments(q, bi);
-       if (bi->bi_phys_segments > q->max_phys_segments)
+       if (bi->bi_phys_segments > queue_max_phys_segments(q))
                return 0;
 
        if (q->merge_bvec_fn)
index de143deb06f0bcbb1dc1da9e738e88cffd431491..7847bbc1440d6edd912e918821c248c6e20d0ee7 100644 (file)
@@ -672,15 +672,14 @@ try_again:
                                               msb->req_sg);
 
                if (!msb->seg_count) {
-                       chunk = __blk_end_request(msb->block_req, -ENOMEM,
-                                       blk_rq_cur_bytes(msb->block_req));
+                       chunk = __blk_end_request_cur(msb->block_req, -ENOMEM);
                        continue;
                }
 
-               t_sec = msb->block_req->sector << 9;
+               t_sec = blk_rq_pos(msb->block_req) << 9;
                sector_div(t_sec, msb->page_size);
 
-               count = msb->block_req->nr_sectors << 9;
+               count = blk_rq_bytes(msb->block_req);
                count /= msb->page_size;
 
                param.system = msb->system;
@@ -705,8 +704,8 @@ try_again:
                return 0;
        }
 
-       dev_dbg(&card->dev, "elv_next\n");
-       msb->block_req = elv_next_request(msb->queue);
+       dev_dbg(&card->dev, "blk_fetch\n");
+       msb->block_req = blk_fetch_request(msb->queue);
        if (!msb->block_req) {
                dev_dbg(&card->dev, "issue end\n");
                return -EAGAIN;
@@ -745,7 +744,7 @@ static int mspro_block_complete_req(struct memstick_dev *card, int error)
                                        t_len *= msb->page_size;
                        }
                } else
-                       t_len = msb->block_req->nr_sectors << 9;
+                       t_len = blk_rq_bytes(msb->block_req);
 
                dev_dbg(&card->dev, "transferred %x (%d)\n", t_len, error);
 
@@ -825,8 +824,8 @@ static void mspro_block_submit_req(struct request_queue *q)
                return;
 
        if (msb->eject) {
-               while ((req = elv_next_request(q)) != NULL)
-                       __blk_end_request(req, -ENODEV, blk_rq_bytes(req));
+               while ((req = blk_fetch_request(q)) != NULL)
+                       __blk_end_request_all(req, -ENODEV);
 
                return;
        }
@@ -1243,7 +1242,7 @@ static int mspro_block_init_disk(struct memstick_dev *card)
 
        sprintf(msb->disk->disk_name, "mspblk%d", disk_id);
 
-       blk_queue_hardsect_size(msb->queue, msb->page_size);
+       blk_queue_logical_block_size(msb->queue, msb->page_size);
 
        capacity = be16_to_cpu(sys_info->user_block_count);
        capacity *= be16_to_cpu(sys_info->block_size);
index a9019f081b971b888464166c407a4c8aabb9da30..79f5433359f9b3fc1b346cb78b5d11dcd60d15de 100644 (file)
@@ -1277,8 +1277,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        /* do we need to support multiple segments? */
        if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
                printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
-                   ioc->name, __func__, req->bio->bi_vcnt, req->data_len,
-                   rsp->bio->bi_vcnt, rsp->data_len);
+                   ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req),
+                   rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
                return -EINVAL;
        }
 
@@ -1295,7 +1295,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        smpreq = (SmpPassthroughRequest_t *)mf;
        memset(smpreq, 0, sizeof(*smpreq));
 
-       smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
+       smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
        smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
 
        if (rphy)
@@ -1321,10 +1321,10 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                       MPI_SGE_FLAGS_END_OF_BUFFER |
                       MPI_SGE_FLAGS_DIRECTION |
                       mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
-       flagsLength |= (req->data_len - 4);
+       flagsLength |= (blk_rq_bytes(req) - 4);
 
        dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
-                                     req->data_len, PCI_DMA_BIDIRECTIONAL);
+                                     blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
        if (!dma_addr_out)
                goto put_mf;
        mpt_add_sge(psge, flagsLength, dma_addr_out);
@@ -1332,9 +1332,9 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
        /* response */
        flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
-       flagsLength |= rsp->data_len + 4;
+       flagsLength |= blk_rq_bytes(rsp) + 4;
        dma_addr_in =  pci_map_single(ioc->pcidev, bio_data(rsp->bio),
-                                     rsp->data_len, PCI_DMA_BIDIRECTIONAL);
+                                     blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
        if (!dma_addr_in)
                goto unmap;
        mpt_add_sge(psge, flagsLength, dma_addr_in);
@@ -1357,8 +1357,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
                memcpy(req->sense, smprep, sizeof(*smprep));
                req->sense_len = sizeof(*smprep);
-               req->data_len = 0;
-               rsp->data_len -= smprep->ResponseDataLength;
+               req->resid_len = 0;
+               rsp->resid_len -= smprep->ResponseDataLength;
        } else {
                printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
                    ioc->name, __func__);
@@ -1366,10 +1366,10 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        }
 unmap:
        if (dma_addr_out)
-               pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
+               pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req),
                                 PCI_DMA_BIDIRECTIONAL);
        if (dma_addr_in)
-               pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
+               pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp),
                                 PCI_DMA_BIDIRECTIONAL);
 put_mf:
        if (mf)
index a443e136dc41591136aecc1ec9e863ce43b2e35e..335d4c78a775122ea0e6738aed84a31d7dd4d47b 100644 (file)
@@ -426,15 +426,9 @@ static void i2o_block_end_request(struct request *req, int error,
        struct request_queue *q = req->q;
        unsigned long flags;
 
-       if (blk_end_request(req, error, nr_bytes)) {
-               int leftover = (req->hard_nr_sectors << KERNEL_SECTOR_SHIFT);
-
-               if (blk_pc_request(req))
-                       leftover = req->data_len;
-
+       if (blk_end_request(req, error, nr_bytes))
                if (error)
-                       blk_end_request(req, -EIO, leftover);
-       }
+                       blk_end_request_all(req, -EIO);
 
        spin_lock_irqsave(q->queue_lock, flags);
 
@@ -761,7 +755,7 @@ static int i2o_block_transfer(struct request *req)
                        break;
 
                case CACHE_SMARTFETCH:
-                       if (req->nr_sectors > 16)
+                       if (blk_rq_sectors(req) > 16)
                                ctl_flags = 0x201F0008;
                        else
                                ctl_flags = 0x001F0000;
@@ -781,13 +775,13 @@ static int i2o_block_transfer(struct request *req)
                        ctl_flags = 0x001F0010;
                        break;
                case CACHE_SMARTBACK:
-                       if (req->nr_sectors > 16)
+                       if (blk_rq_sectors(req) > 16)
                                ctl_flags = 0x001F0004;
                        else
                                ctl_flags = 0x001F0010;
                        break;
                case CACHE_SMARTTHROUGH:
-                       if (req->nr_sectors > 16)
+                       if (blk_rq_sectors(req) > 16)
                                ctl_flags = 0x001F0004;
                        else
                                ctl_flags = 0x001F0010;
@@ -800,8 +794,9 @@ static int i2o_block_transfer(struct request *req)
        if (c->adaptec) {
                u8 cmd[10];
                u32 scsi_flags;
-               u16 hwsec = queue_hardsect_size(req->q) >> KERNEL_SECTOR_SHIFT;
+               u16 hwsec;
 
+               hwsec = queue_logical_block_size(req->q) >> KERNEL_SECTOR_SHIFT;
                memset(cmd, 0, 10);
 
                sgl_offset = SGL_OFFSET_12;
@@ -827,22 +822,22 @@ static int i2o_block_transfer(struct request *req)
 
                *mptr++ = cpu_to_le32(scsi_flags);
 
-               *((u32 *) & cmd[2]) = cpu_to_be32(req->sector * hwsec);
-               *((u16 *) & cmd[7]) = cpu_to_be16(req->nr_sectors * hwsec);
+               *((u32 *) & cmd[2]) = cpu_to_be32(blk_rq_pos(req) * hwsec);
+               *((u16 *) & cmd[7]) = cpu_to_be16(blk_rq_sectors(req) * hwsec);
 
                memcpy(mptr, cmd, 10);
                mptr += 4;
-               *mptr++ = cpu_to_le32(req->nr_sectors << KERNEL_SECTOR_SHIFT);
+               *mptr++ = cpu_to_le32(blk_rq_bytes(req));
        } else
 #endif
        {
                msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid);
                *mptr++ = cpu_to_le32(ctl_flags);
-               *mptr++ = cpu_to_le32(req->nr_sectors << KERNEL_SECTOR_SHIFT);
+               *mptr++ = cpu_to_le32(blk_rq_bytes(req));
                *mptr++ =
-                   cpu_to_le32((u32) (req->sector << KERNEL_SECTOR_SHIFT));
+                   cpu_to_le32((u32) (blk_rq_pos(req) << KERNEL_SECTOR_SHIFT));
                *mptr++ =
-                   cpu_to_le32(req->sector >> (32 - KERNEL_SECTOR_SHIFT));
+                   cpu_to_le32(blk_rq_pos(req) >> (32 - KERNEL_SECTOR_SHIFT));
        }
 
        if (!i2o_block_sglist_alloc(c, ireq, &mptr)) {
@@ -883,7 +878,7 @@ static void i2o_block_request_fn(struct request_queue *q)
        struct request *req;
 
        while (!blk_queue_plugged(q)) {
-               req = elv_next_request(q);
+               req = blk_peek_request(q);
                if (!req)
                        break;
 
@@ -896,7 +891,7 @@ static void i2o_block_request_fn(struct request_queue *q)
 
                        if (queue_depth < I2O_BLOCK_MAX_OPEN_REQUESTS) {
                                if (!i2o_block_transfer(req)) {
-                                       blkdev_dequeue_request(req);
+                                       blk_start_request(req);
                                        continue;
                                } else
                                        osm_info("transfer error\n");
@@ -922,8 +917,10 @@ static void i2o_block_request_fn(struct request_queue *q)
                                blk_stop_queue(q);
                                break;
                        }
-               } else
-                       end_request(req, 0);
+               } else {
+                       blk_start_request(req);
+                       __blk_end_request_all(req, -EIO);
+               }
        }
 };
 
@@ -1082,7 +1079,7 @@ static int i2o_block_probe(struct device *dev)
         */
        if (!i2o_parm_field_get(i2o_dev, 0x0004, 1, &blocksize, 4) ||
            !i2o_parm_field_get(i2o_dev, 0x0000, 3, &blocksize, 4)) {
-               blk_queue_hardsect_size(queue, le32_to_cpu(blocksize));
+               blk_queue_logical_block_size(queue, le32_to_cpu(blocksize));
        } else
                osm_warn("unable to get blocksize of %s\n", gd->disk_name);
 
index b25e9b6516ae6942d6e9a0c34fc3f0dba0f9556a..98ffc41eaf2c631bebdfed37a9847b17f28b97cd 100644 (file)
@@ -243,7 +243,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                brq.mrq.cmd = &brq.cmd;
                brq.mrq.data = &brq.data;
 
-               brq.cmd.arg = req->sector;
+               brq.cmd.arg = blk_rq_pos(req);
                if (!mmc_card_blockaddr(card))
                        brq.cmd.arg <<= 9;
                brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
@@ -251,7 +251,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                brq.stop.opcode = MMC_STOP_TRANSMISSION;
                brq.stop.arg = 0;
                brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-               brq.data.blocks = req->nr_sectors;
+               brq.data.blocks = blk_rq_sectors(req);
 
                /*
                 * The block layer doesn't support all sector count
@@ -301,7 +301,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                 * Adjust the sg list so it is the same size as the
                 * request.
                 */
-               if (brq.data.blocks != req->nr_sectors) {
+               if (brq.data.blocks != blk_rq_sectors(req)) {
                        int i, data_size = brq.data.blocks << 9;
                        struct scatterlist *sg;
 
@@ -352,8 +352,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                        printk(KERN_ERR "%s: error %d transferring data,"
                               " sector %u, nr %u, card status %#x\n",
                               req->rq_disk->disk_name, brq.data.error,
-                              (unsigned)req->sector,
-                              (unsigned)req->nr_sectors, status);
+                              (unsigned)blk_rq_pos(req),
+                              (unsigned)blk_rq_sectors(req), status);
                }
 
                if (brq.stop.error) {
@@ -521,7 +521,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 
        sprintf(md->disk->disk_name, "mmcblk%d", devidx);
 
-       blk_queue_hardsect_size(md->queue.queue, 512);
+       blk_queue_logical_block_size(md->queue.queue, 512);
 
        if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
                /*
index 7a72e75d5c674b94a66ab16073acb89e96a6d42b..49e582356c65ab34bc17b1db1bbae002bc5faaff 100644 (file)
@@ -55,7 +55,7 @@ static int mmc_queue_thread(void *d)
                spin_lock_irq(q->queue_lock);
                set_current_state(TASK_INTERRUPTIBLE);
                if (!blk_queue_plugged(q))
-                       req = elv_next_request(q);
+                       req = blk_fetch_request(q);
                mq->req = req;
                spin_unlock_irq(q->queue_lock);
 
@@ -88,16 +88,11 @@ static void mmc_request(struct request_queue *q)
 {
        struct mmc_queue *mq = q->queuedata;
        struct request *req;
-       int ret;
 
        if (!mq) {
                printk(KERN_ERR "MMC: killing requests for dead queue\n");
-               while ((req = elv_next_request(q)) != NULL) {
-                       do {
-                               ret = __blk_end_request(req, -EIO,
-                                                       blk_rq_cur_bytes(req));
-                       } while (ret);
-               }
+               while ((req = blk_fetch_request(q)) != NULL)
+                       __blk_end_request_all(req, -EIO);
                return;
        }
 
index a49a9c8f2cb1faffe5c16d782ea793839062dcc4..aaac3b6800b7358dd1597df13c0ea781d3215031 100644 (file)
@@ -47,40 +47,41 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
        unsigned long block, nsect;
        char *buf;
 
-       block = req->sector << 9 >> tr->blkshift;
-       nsect = req->current_nr_sectors << 9 >> tr->blkshift;
+       block = blk_rq_pos(req) << 9 >> tr->blkshift;
+       nsect = blk_rq_cur_bytes(req) >> tr->blkshift;
 
        buf = req->buffer;
 
        if (req->cmd_type == REQ_TYPE_LINUX_BLOCK &&
            req->cmd[0] == REQ_LB_OP_DISCARD)
-               return !tr->discard(dev, block, nsect);
+               return tr->discard(dev, block, nsect);
 
        if (!blk_fs_request(req))
-               return 0;
+               return -EIO;
 
-       if (req->sector + req->current_nr_sectors > get_capacity(req->rq_disk))
-               return 0;
+       if (blk_rq_pos(req) + blk_rq_cur_sectors(req) >
+           get_capacity(req->rq_disk))
+               return -EIO;
 
        switch(rq_data_dir(req)) {
        case READ:
                for (; nsect > 0; nsect--, block++, buf += tr->blksize)
                        if (tr->readsect(dev, block, buf))
-                               return 0;
-               return 1;
+                               return -EIO;
+               return 0;
 
        case WRITE:
                if (!tr->writesect)
-                       return 0;
+                       return -EIO;
 
                for (; nsect > 0; nsect--, block++, buf += tr->blksize)
                        if (tr->writesect(dev, block, buf))
-                               return 0;
-               return 1;
+                               return -EIO;
+               return 0;
 
        default:
                printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req));
-               return 0;
+               return -EIO;
        }
 }
 
@@ -88,19 +89,18 @@ static int mtd_blktrans_thread(void *arg)
 {
        struct mtd_blktrans_ops *tr = arg;
        struct request_queue *rq = tr->blkcore_priv->rq;
+       struct request *req = NULL;
 
        /* we might get involved when memory gets low, so use PF_MEMALLOC */
        current->flags |= PF_MEMALLOC;
 
        spin_lock_irq(rq->queue_lock);
+
        while (!kthread_should_stop()) {
-               struct request *req;
                struct mtd_blktrans_dev *dev;
-               int res = 0;
-
-               req = elv_next_request(rq);
+               int res;
 
-               if (!req) {
+               if (!req && !(req = blk_fetch_request(rq))) {
                        set_current_state(TASK_INTERRUPTIBLE);
                        spin_unlock_irq(rq->queue_lock);
                        schedule();
@@ -119,8 +119,13 @@ static int mtd_blktrans_thread(void *arg)
 
                spin_lock_irq(rq->queue_lock);
 
-               end_request(req, res);
+               if (!__blk_end_request_cur(req, res))
+                       req = NULL;
        }
+
+       if (req)
+               __blk_end_request_all(req, -EIO);
+
        spin_unlock_irq(rq->queue_lock);
 
        return 0;
@@ -373,7 +378,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
        }
 
        tr->blkcore_priv->rq->queuedata = tr;
-       blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize);
+       blk_queue_logical_block_size(tr->blkcore_priv->rq, tr->blksize);
        if (tr->discard)
                blk_queue_set_discard(tr->blkcore_priv->rq,
                                      blktrans_discard_request);
index 73348c4047e98d249a9a576b87f2e8d44edaf623..4a9cc92d4d1867469dcae3efed4c468b251ff7f8 100644 (file)
@@ -702,7 +702,7 @@ static unsigned int iosapic_startup_irq(unsigned int irq)
 }
 
 #ifdef CONFIG_SMP
-static void iosapic_set_affinity_irq(unsigned int irq,
+static int iosapic_set_affinity_irq(unsigned int irq,
                                     const struct cpumask *dest)
 {
        struct vector_info *vi = iosapic_get_vector(irq);
@@ -712,7 +712,7 @@ static void iosapic_set_affinity_irq(unsigned int irq,
 
        dest_cpu = cpu_check_affinity(irq, dest);
        if (dest_cpu < 0)
-               return;
+               return -1;
 
        cpumask_copy(irq_desc[irq].affinity, cpumask_of(dest_cpu));
        vi->txn_addr = txn_affinity_addr(irq, dest_cpu);
@@ -724,6 +724,8 @@ static void iosapic_set_affinity_irq(unsigned int irq,
        iosapic_set_irt_data(vi, &dummy_d0, &d1);
        iosapic_wr_irt_entry(vi, d0, d1);
        spin_unlock_irqrestore(&iosapic_lock, flags);
+
+       return 0;
 }
 #endif
 
index 4e63cc9e277827bfe74db6a778471dc92196cc25..151bf5bc8afe968d196702bad526c38b2797a4f8 100644 (file)
@@ -1,5 +1,5 @@
 /* Low-level parallel-port routines for 8255-based PC-style hardware.
- * 
+ *
  * Authors: Phil Blundell <philb@gnu.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *         Jose Renau <renau@acm.org>
@@ -11,7 +11,7 @@
  * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
  * DMA support - Bert De Jonghe <bert@sophis.be>
  * Many ECP bugs fixed.  Fred Barnes & Jamie Lokier, 1999
- * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G. 
+ * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G.
  * Various hacks, Fred Barnes, 04/2001
  * Updated probing logic - Adam Belay <ambx1@neo.rr.com>
  */
 #include <linux/pnp.h>
 #include <linux/platform_device.h>
 #include <linux/sysctl.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
 
-#include <asm/io.h>
 #include <asm/dma.h>
-#include <asm/uaccess.h>
 
 #include <linux/parport.h>
 #include <linux/parport_pc.h>
@@ -82,7 +82,7 @@
 #define ECR_TST 06
 #define ECR_CNF 07
 #define ECR_MODE_MASK 0xe0
-#define ECR_WRITE(p,v) frob_econtrol((p),0xff,(v))
+#define ECR_WRITE(p, v) frob_econtrol((p), 0xff, (v))
 
 #undef DEBUG
 
@@ -109,27 +109,27 @@ static int pci_registered_parport;
 static int pnp_registered_parport;
 
 /* frob_control, but for ECR */
-static void frob_econtrol (struct parport *pb, unsigned char m,
+static void frob_econtrol(struct parport *pb, unsigned char m,
                           unsigned char v)
 {
        unsigned char ectr = 0;
 
        if (m != 0xff)
-               ectr = inb (ECONTROL (pb));
+               ectr = inb(ECONTROL(pb));
 
-       DPRINTK (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n",
+       DPRINTK(KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n",
                m, v, ectr, (ectr & ~m) ^ v);
 
-       outb ((ectr & ~m) ^ v, ECONTROL (pb));
+       outb((ectr & ~m) ^ v, ECONTROL(pb));
 }
 
-static __inline__ void frob_set_mode (struct parport *p, int mode)
+static inline void frob_set_mode(struct parport *p, int mode)
 {
-       frob_econtrol (p, ECR_MODE_MASK, mode << 5);
+       frob_econtrol(p, ECR_MODE_MASK, mode << 5);
 }
 
 #ifdef CONFIG_PARPORT_PC_FIFO
-/* Safely change the mode bits in the ECR 
+/* Safely change the mode bits in the ECR
    Returns:
            0    : Success
           -EBUSY: Could not drain FIFO in some finite amount of time,
@@ -141,17 +141,18 @@ static int change_mode(struct parport *p, int m)
        unsigned char oecr;
        int mode;
 
-       DPRINTK(KERN_INFO "parport change_mode ECP-ISA to mode 0x%02x\n",m);
+       DPRINTK(KERN_INFO "parport change_mode ECP-ISA to mode 0x%02x\n", m);
 
        if (!priv->ecr) {
-               printk (KERN_DEBUG "change_mode: but there's no ECR!\n");
+               printk(KERN_DEBUG "change_mode: but there's no ECR!\n");
                return 0;
        }
 
        /* Bits <7:5> contain the mode. */
-       oecr = inb (ECONTROL (p));
+       oecr = inb(ECONTROL(p));
        mode = (oecr >> 5) & 0x7;
-       if (mode == m) return 0;
+       if (mode == m)
+               return 0;
 
        if (mode >= 2 && !(priv->ctr & 0x20)) {
                /* This mode resets the FIFO, so we may
@@ -163,19 +164,21 @@ static int change_mode(struct parport *p, int m)
                case ECR_ECP: /* ECP Parallel Port mode */
                        /* Busy wait for 200us */
                        for (counter = 0; counter < 40; counter++) {
-                               if (inb (ECONTROL (p)) & 0x01)
+                               if (inb(ECONTROL(p)) & 0x01)
+                                       break;
+                               if (signal_pending(current))
                                        break;
-                               if (signal_pending (current)) break;
-                               udelay (5);
+                               udelay(5);
                        }
 
                        /* Poll slowly. */
-                       while (!(inb (ECONTROL (p)) & 0x01)) {
-                               if (time_after_eq (jiffies, expire))
+                       while (!(inb(ECONTROL(p)) & 0x01)) {
+                               if (time_after_eq(jiffies, expire))
                                        /* The FIFO is stuck. */
                                        return -EBUSY;
-                               schedule_timeout_interruptible(msecs_to_jiffies(10));
-                               if (signal_pending (current))
+                               schedule_timeout_interruptible(
+                                                       msecs_to_jiffies(10));
+                               if (signal_pending(current))
                                        break;
                        }
                }
@@ -185,20 +188,20 @@ static int change_mode(struct parport *p, int m)
                /* We have to go through mode 001 */
                oecr &= ~(7 << 5);
                oecr |= ECR_PS2 << 5;
-               ECR_WRITE (p, oecr);
+               ECR_WRITE(p, oecr);
        }
 
        /* Set the mode. */
        oecr &= ~(7 << 5);
        oecr |= m << 5;
-       ECR_WRITE (p, oecr);
+       ECR_WRITE(p, oecr);
        return 0;
 }
 
 #ifdef CONFIG_PARPORT_1284
 /* Find FIFO lossage; FIFO is reset */
 #if 0
-static int get_fifo_residue (struct parport *p)
+static int get_fifo_residue(struct parport *p)
 {
        int residue;
        int cnfga;
@@ -206,26 +209,26 @@ static int get_fifo_residue (struct parport *p)
 
        /* Adjust for the contents of the FIFO. */
        for (residue = priv->fifo_depth; ; residue--) {
-               if (inb (ECONTROL (p)) & 0x2)
+               if (inb(ECONTROL(p)) & 0x2)
                                /* Full up. */
                        break;
 
-               outb (0, FIFO (p));
+               outb(0, FIFO(p));
        }
 
-       printk (KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name,
+       printk(KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name,
                residue);
 
        /* Reset the FIFO. */
-       frob_set_mode (p, ECR_PS2);
+       frob_set_mode(p, ECR_PS2);
 
        /* Now change to config mode and clean up. FIXME */
-       frob_set_mode (p, ECR_CNF);
-       cnfga = inb (CONFIGA (p));
-       printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
+       frob_set_mode(p, ECR_CNF);
+       cnfga = inb(CONFIGA(p));
+       printk(KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
 
        if (!(cnfga & (1<<2))) {
-               printk (KERN_DEBUG "%s: Accounting for extra byte\n", p->name);
+               printk(KERN_DEBUG "%s: Accounting for extra byte\n", p->name);
                residue++;
        }
 
@@ -233,9 +236,11 @@ static int get_fifo_residue (struct parport *p)
         * PWord != 1 byte. */
 
        /* Back to PS2 mode. */
-       frob_set_mode (p, ECR_PS2);
+       frob_set_mode(p, ECR_PS2);
 
-       DPRINTK (KERN_DEBUG "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n", inb (ECONTROL (p)));
+       DPRINTK(KERN_DEBUG
+            "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n",
+                                                       inb(ECONTROL(p)));
        return residue;
 }
 #endif  /*  0 */
@@ -257,8 +262,8 @@ static int clear_epp_timeout(struct parport *pb)
        /* To clear timeout some chips require double read */
        parport_pc_read_status(pb);
        r = parport_pc_read_status(pb);
-       outb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */
-       outb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */
+       outb(r | 0x01, STATUS(pb)); /* Some reset by writing 1 */
+       outb(r & 0xfe, STATUS(pb)); /* Others by writing 0 */
        r = parport_pc_read_status(pb);
 
        return !(r & 0x01);
@@ -272,7 +277,8 @@ static int clear_epp_timeout(struct parport *pb)
  * of these are in parport_pc.h.
  */
 
-static void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
+static void parport_pc_init_state(struct pardevice *dev,
+                                               struct parport_state *s)
 {
        s->u.pc.ctr = 0xc;
        if (dev->irq_func &&
@@ -289,22 +295,23 @@ static void parport_pc_save_state(struct parport *p, struct parport_state *s)
        const struct parport_pc_private *priv = p->physport->private_data;
        s->u.pc.ctr = priv->ctr;
        if (priv->ecr)
-               s->u.pc.ecr = inb (ECONTROL (p));
+               s->u.pc.ecr = inb(ECONTROL(p));
 }
 
-static void parport_pc_restore_state(struct parport *p, struct parport_state *s)
+static void parport_pc_restore_state(struct parport *p,
+                                               struct parport_state *s)
 {
        struct parport_pc_private *priv = p->physport->private_data;
        register unsigned char c = s->u.pc.ctr & priv->ctr_writable;
-       outb (c, CONTROL (p));
+       outb(c, CONTROL(p));
        priv->ctr = c;
        if (priv->ecr)
-               ECR_WRITE (p, s->u.pc.ecr);
+               ECR_WRITE(p, s->u.pc.ecr);
 }
 
 #ifdef CONFIG_PARPORT_1284
-static size_t parport_pc_epp_read_data (struct parport *port, void *buf,
-                                       size_t length, int flags)
+static size_t parport_pc_epp_read_data(struct parport *port, void *buf,
+                                      size_t length, int flags)
 {
        size_t got = 0;
 
@@ -316,54 +323,52 @@ static size_t parport_pc_epp_read_data (struct parport *port, void *buf,
                 *  nFault is 0 if there is at least 1 byte in the Warp's FIFO
                 *  pError is 1 if there are 16 bytes in the Warp's FIFO
                 */
-               status = inb (STATUS (port));
+               status = inb(STATUS(port));
 
-               while (!(status & 0x08) && (got < length)) {
-                       if ((left >= 16) && (status & 0x20) && !(status & 0x08)) {
+               while (!(status & 0x08) && got < length) {
+                       if (left >= 16 && (status & 0x20) && !(status & 0x08)) {
                                /* can grab 16 bytes from warp fifo */
-                               if (!((long)buf & 0x03)) {
-                                       insl (EPPDATA (port), buf, 4);
-                               } else {
-                                       insb (EPPDATA (port), buf, 16);
-                               }
+                               if (!((long)buf & 0x03))
+                                       insl(EPPDATA(port), buf, 4);
+                               else
+                                       insb(EPPDATA(port), buf, 16);
                                buf += 16;
                                got += 16;
                                left -= 16;
                        } else {
                                /* grab single byte from the warp fifo */
-                               *((char *)buf) = inb (EPPDATA (port));
+                               *((char *)buf) = inb(EPPDATA(port));
                                buf++;
                                got++;
                                left--;
                        }
-                       status = inb (STATUS (port));
+                       status = inb(STATUS(port));
                        if (status & 0x01) {
                                /* EPP timeout should never occur... */
-                               printk (KERN_DEBUG "%s: EPP timeout occurred while talking to "
-                                       "w91284pic (should not have done)\n", port->name);
-                               clear_epp_timeout (port);
+                               printk(KERN_DEBUG
+"%s: EPP timeout occurred while talking to w91284pic (should not have done)\n", port->name);
+                               clear_epp_timeout(port);
                        }
                }
                return got;
        }
        if ((flags & PARPORT_EPP_FAST) && (length > 1)) {
-               if (!(((long)buf | length) & 0x03)) {
-                       insl (EPPDATA (port), buf, (length >> 2));
-               } else {
-                       insb (EPPDATA (port), buf, length);
-               }
-               if (inb (STATUS (port)) & 0x01) {
-                       clear_epp_timeout (port);
+               if (!(((long)buf | length) & 0x03))
+                       insl(EPPDATA(port), buf, (length >> 2));
+               else
+                       insb(EPPDATA(port), buf, length);
+               if (inb(STATUS(port)) & 0x01) {
+                       clear_epp_timeout(port);
                        return -EIO;
                }
                return length;
        }
        for (; got < length; got++) {
-               *((char*)buf) = inb (EPPDATA(port));
+               *((char *)buf) = inb(EPPDATA(port));
                buf++;
-               if (inb (STATUS (port)) & 0x01) {
+               if (inb(STATUS(port)) & 0x01) {
                        /* EPP timeout */
-                       clear_epp_timeout (port);
+                       clear_epp_timeout(port);
                        break;
                }
        }
@@ -371,28 +376,27 @@ static size_t parport_pc_epp_read_data (struct parport *port, void *buf,
        return got;
 }
 
-static size_t parport_pc_epp_write_data (struct parport *port, const void *buf,
-                                        size_t length, int flags)
+static size_t parport_pc_epp_write_data(struct parport *port, const void *buf,
+                                       size_t length, int flags)
 {
        size_t written = 0;
 
        if ((flags & PARPORT_EPP_FAST) && (length > 1)) {
-               if (!(((long)buf | length) & 0x03)) {
-                       outsl (EPPDATA (port), buf, (length >> 2));
-               } else {
-                       outsb (EPPDATA (port), buf, length);
-               }
-               if (inb (STATUS (port)) & 0x01) {
-                       clear_epp_timeout (port);
+               if (!(((long)buf | length) & 0x03))
+                       outsl(EPPDATA(port), buf, (length >> 2));
+               else
+                       outsb(EPPDATA(port), buf, length);
+               if (inb(STATUS(port)) & 0x01) {
+                       clear_epp_timeout(port);
                        return -EIO;
                }
                return length;
        }
        for (; written < length; written++) {
-               outb (*((char*)buf), EPPDATA(port));
+               outb(*((char *)buf), EPPDATA(port));
                buf++;
-               if (inb (STATUS(port)) & 0x01) {
-                       clear_epp_timeout (port);
+               if (inb(STATUS(port)) & 0x01) {
+                       clear_epp_timeout(port);
                        break;
                }
        }
@@ -400,24 +404,24 @@ static size_t parport_pc_epp_write_data (struct parport *port, const void *buf,
        return written;
 }
 
-static size_t parport_pc_epp_read_addr (struct parport *port, void *buf,
+static size_t parport_pc_epp_read_addr(struct parport *port, void *buf,
                                        size_t length, int flags)
 {
        size_t got = 0;
 
        if ((flags & PARPORT_EPP_FAST) && (length > 1)) {
-               insb (EPPADDR (port), buf, length);
-               if (inb (STATUS (port)) & 0x01) {
-                       clear_epp_timeout (port);
+               insb(EPPADDR(port), buf, length);
+               if (inb(STATUS(port)) & 0x01) {
+                       clear_epp_timeout(port);
                        return -EIO;
                }
                return length;
        }
        for (; got < length; got++) {
-               *((char*)buf) = inb (EPPADDR (port));
+               *((char *)buf) = inb(EPPADDR(port));
                buf++;
-               if (inb (STATUS (port)) & 0x01) {
-                       clear_epp_timeout (port);
+               if (inb(STATUS(port)) & 0x01) {
+                       clear_epp_timeout(port);
                        break;
                }
        }
@@ -425,25 +429,25 @@ static size_t parport_pc_epp_read_addr (struct parport *port, void *buf,
        return got;
 }
 
-static size_t parport_pc_epp_write_addr (struct parport *port,
+static size_t parport_pc_epp_write_addr(struct parport *port,
                                         const void *buf, size_t length,
                                         int flags)
 {
        size_t written = 0;
 
        if ((flags & PARPORT_EPP_FAST) && (length > 1)) {
-               outsb (EPPADDR (port), buf, length);
-               if (inb (STATUS (port)) & 0x01) {
-                       clear_epp_timeout (port);
+               outsb(EPPADDR(port), buf, length);
+               if (inb(STATUS(port)) & 0x01) {
+                       clear_epp_timeout(port);
                        return -EIO;
                }
                return length;
        }
        for (; written < length; written++) {
-               outb (*((char*)buf), EPPADDR (port));
+               outb(*((char *)buf), EPPADDR(port));
                buf++;
-               if (inb (STATUS (port)) & 0x01) {
-                       clear_epp_timeout (port);
+               if (inb(STATUS(port)) & 0x01) {
+                       clear_epp_timeout(port);
                        break;
                }
        }
@@ -451,74 +455,74 @@ static size_t parport_pc_epp_write_addr (struct parport *port,
        return written;
 }
 
-static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf,
-                                          size_t length, int flags)
+static size_t parport_pc_ecpepp_read_data(struct parport *port, void *buf,
+                                         size_t length, int flags)
 {
        size_t got;
 
-       frob_set_mode (port, ECR_EPP);
-       parport_pc_data_reverse (port);
-       parport_pc_write_control (port, 0x4);
-       got = parport_pc_epp_read_data (port, buf, length, flags);
-       frob_set_mode (port, ECR_PS2);
+       frob_set_mode(port, ECR_EPP);
+       parport_pc_data_reverse(port);
+       parport_pc_write_control(port, 0x4);
+       got = parport_pc_epp_read_data(port, buf, length, flags);
+       frob_set_mode(port, ECR_PS2);
 
        return got;
 }
 
-static size_t parport_pc_ecpepp_write_data (struct parport *port,
-                                           const void *buf, size_t length,
-                                           int flags)
+static size_t parport_pc_ecpepp_write_data(struct parport *port,
+                                          const void *buf, size_t length,
+                                          int flags)
 {
        size_t written;
 
-       frob_set_mode (port, ECR_EPP);
-       parport_pc_write_control (port, 0x4);
-       parport_pc_data_forward (port);
-       written = parport_pc_epp_write_data (port, buf, length, flags);
-       frob_set_mode (port, ECR_PS2);
+       frob_set_mode(port, ECR_EPP);
+       parport_pc_write_control(port, 0x4);
+       parport_pc_data_forward(port);
+       written = parport_pc_epp_write_data(port, buf, length, flags);
+       frob_set_mode(port, ECR_PS2);
 
        return written;
 }
 
-static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf,
-                                          size_t length, int flags)
+static size_t parport_pc_ecpepp_read_addr(struct parport *port, void *buf,
+                                         size_t length, int flags)
 {
        size_t got;
 
-       frob_set_mode (port, ECR_EPP);
-       parport_pc_data_reverse (port);
-       parport_pc_write_control (port, 0x4);
-       got = parport_pc_epp_read_addr (port, buf, length, flags);
-       frob_set_mode (port, ECR_PS2);
+       frob_set_mode(port, ECR_EPP);
+       parport_pc_data_reverse(port);
+       parport_pc_write_control(port, 0x4);
+       got = parport_pc_epp_read_addr(port, buf, length, flags);
+       frob_set_mode(port, ECR_PS2);
 
        return got;
 }
 
-static size_t parport_pc_ecpepp_write_addr (struct parport *port,
+static size_t parport_pc_ecpepp_write_addr(struct parport *port,
                                            const void *buf, size_t length,
                                            int flags)
 {
        size_t written;
 
-       frob_set_mode (port, ECR_EPP);
-       parport_pc_write_control (port, 0x4);
-       parport_pc_data_forward (port);
-       written = parport_pc_epp_write_addr (port, buf, length, flags);
-       frob_set_mode (port, ECR_PS2);
+       frob_set_mode(port, ECR_EPP);
+       parport_pc_write_control(port, 0x4);
+       parport_pc_data_forward(port);
+       written = parport_pc_epp_write_addr(port, buf, length, flags);
+       frob_set_mode(port, ECR_PS2);
 
        return written;
 }
 #endif /* IEEE 1284 support */
 
 #ifdef CONFIG_PARPORT_PC_FIFO
-static size_t parport_pc_fifo_write_block_pio (struct parport *port,
+static size_t parport_pc_fifo_write_block_pio(struct parport *port,
                                               const void *buf, size_t length)
 {
        int ret = 0;
        const unsigned char *bufp = buf;
        size_t left = length;
        unsigned long expire = jiffies + port->physport->cad->timeout;
-       const int fifo = FIFO (port);
+       const int fifo = FIFO(port);
        int poll_for = 8; /* 80 usecs */
        const struct parport_pc_private *priv = port->physport->private_data;
        const int fifo_depth = priv->fifo_depth;
@@ -526,25 +530,25 @@ static size_t parport_pc_fifo_write_block_pio (struct parport *port,
        port = port->physport;
 
        /* We don't want to be interrupted every character. */
-       parport_pc_disable_irq (port);
+       parport_pc_disable_irq(port);
        /* set nErrIntrEn and serviceIntr */
-       frob_econtrol (port, (1<<4) | (1<<2), (1<<4) | (1<<2));
+       frob_econtrol(port, (1<<4) | (1<<2), (1<<4) | (1<<2));
 
        /* Forward mode. */
-       parport_pc_data_forward (port); /* Must be in PS2 mode */
+       parport_pc_data_forward(port); /* Must be in PS2 mode */
 
        while (left) {
                unsigned char byte;
-               unsigned char ecrval = inb (ECONTROL (port));
+               unsigned char ecrval = inb(ECONTROL(port));
                int i = 0;
 
-               if (need_resched() && time_before (jiffies, expire))
+               if (need_resched() && time_before(jiffies, expire))
                        /* Can't yield the port. */
-                       schedule ();
+                       schedule();
 
                /* Anyone else waiting for the port? */
                if (port->waithead) {
-                       printk (KERN_DEBUG "Somebody wants the port\n");
+                       printk(KERN_DEBUG "Somebody wants the port\n");
                        break;
                }
 
@@ -552,21 +556,22 @@ static size_t parport_pc_fifo_write_block_pio (struct parport *port,
                        /* FIFO is full. Wait for interrupt. */
 
                        /* Clear serviceIntr */
-                       ECR_WRITE (port, ecrval & ~(1<<2));
-               false_alarm:
-                       ret = parport_wait_event (port, HZ);
-                       if (ret < 0) break;
+                       ECR_WRITE(port, ecrval & ~(1<<2));
+false_alarm:
+                       ret = parport_wait_event(port, HZ);
+                       if (ret < 0)
+                               break;
                        ret = 0;
-                       if (!time_before (jiffies, expire)) {
+                       if (!time_before(jiffies, expire)) {
                                /* Timed out. */
-                               printk (KERN_DEBUG "FIFO write timed out\n");
+                               printk(KERN_DEBUG "FIFO write timed out\n");
                                break;
                        }
-                       ecrval = inb (ECONTROL (port));
+                       ecrval = inb(ECONTROL(port));
                        if (!(ecrval & (1<<2))) {
                                if (need_resched() &&
-                                   time_before (jiffies, expire))
-                                       schedule ();
+                                   time_before(jiffies, expire))
+                                       schedule();
 
                                goto false_alarm;
                        }
@@ -577,38 +582,38 @@ static size_t parport_pc_fifo_write_block_pio (struct parport *port,
                /* Can't fail now. */
                expire = jiffies + port->cad->timeout;
 
-       poll:
-               if (signal_pending (current))
+poll:
+               if (signal_pending(current))
                        break;
 
                if (ecrval & 0x01) {
                        /* FIFO is empty. Blast it full. */
                        const int n = left < fifo_depth ? left : fifo_depth;
-                       outsb (fifo, bufp, n);
+                       outsb(fifo, bufp, n);
                        bufp += n;
                        left -= n;
 
                        /* Adjust the poll time. */
-                       if (i < (poll_for - 2)) poll_for--;
+                       if (i < (poll_for - 2))
+                               poll_for--;
                        continue;
                } else if (i++ < poll_for) {
-                       udelay (10);
-                       ecrval = inb (ECONTROL (port));
+                       udelay(10);
+                       ecrval = inb(ECONTROL(port));
                        goto poll;
                }
 
-               /* Half-full (call me an optimist) */
+               /* Half-full(call me an optimist) */
                byte = *bufp++;
-               outb (byte, fifo);
+               outb(byte, fifo);
                left--;
-        }
-
-dump_parport_state ("leave fifo_write_block_pio", port);
+       }
+       dump_parport_state("leave fifo_write_block_pio", port);
        return length - left;
 }
 
 #ifdef HAS_DMA
-static size_t parport_pc_fifo_write_block_dma (struct parport *port,
+static size_t parport_pc_fifo_write_block_dma(struct parport *port,
                                               const void *buf, size_t length)
 {
        int ret = 0;
@@ -621,7 +626,7 @@ static size_t parport_pc_fifo_write_block_dma (struct parport *port,
        unsigned long start = (unsigned long) buf;
        unsigned long end = (unsigned long) buf + length - 1;
 
-dump_parport_state ("enter fifo_write_block_dma", port);
+       dump_parport_state("enter fifo_write_block_dma", port);
        if (end < MAX_DMA_ADDRESS) {
                /* If it would cross a 64k boundary, cap it at the end. */
                if ((start ^ end) & ~0xffffUL)
@@ -629,8 +634,9 @@ dump_parport_state ("enter fifo_write_block_dma", port);
 
                dma_addr = dma_handle = dma_map_single(dev, (void *)buf, length,
                                                       DMA_TO_DEVICE);
-        } else {
-               /* above 16 MB we use a bounce buffer as ISA-DMA is not possible */
+       } else {
+               /* above 16 MB we use a bounce buffer as ISA-DMA
+                  is not possible */
                maxlen   = PAGE_SIZE;          /* sizeof(priv->dma_buf) */
                dma_addr = priv->dma_handle;
                dma_handle = 0;
@@ -639,12 +645,12 @@ dump_parport_state ("enter fifo_write_block_dma", port);
        port = port->physport;
 
        /* We don't want to be interrupted every character. */
-       parport_pc_disable_irq (port);
+       parport_pc_disable_irq(port);
        /* set nErrIntrEn and serviceIntr */
-       frob_econtrol (port, (1<<4) | (1<<2), (1<<4) | (1<<2));
+       frob_econtrol(port, (1<<4) | (1<<2), (1<<4) | (1<<2));
 
        /* Forward mode. */
-       parport_pc_data_forward (port); /* Must be in PS2 mode */
+       parport_pc_data_forward(port); /* Must be in PS2 mode */
 
        while (left) {
                unsigned long expire = jiffies + port->physport->cad->timeout;
@@ -665,10 +671,10 @@ dump_parport_state ("enter fifo_write_block_dma", port);
                set_dma_count(port->dma, count);
 
                /* Set DMA mode */
-               frob_econtrol (port, 1<<3, 1<<3);
+               frob_econtrol(port, 1<<3, 1<<3);
 
                /* Clear serviceIntr */
-               frob_econtrol (port, 1<<2, 0);
+               frob_econtrol(port, 1<<2, 0);
 
                enable_dma(port->dma);
                release_dma_lock(dmaflag);
@@ -676,20 +682,22 @@ dump_parport_state ("enter fifo_write_block_dma", port);
                /* assume DMA will be successful */
                left -= count;
                buf  += count;
-               if (dma_handle) dma_addr += count;
+               if (dma_handle)
+                       dma_addr += count;
 
                /* Wait for interrupt. */
-       false_alarm:
-               ret = parport_wait_event (port, HZ);
-               if (ret < 0) break;
+false_alarm:
+               ret = parport_wait_event(port, HZ);
+               if (ret < 0)
+                       break;
                ret = 0;
-               if (!time_before (jiffies, expire)) {
+               if (!time_before(jiffies, expire)) {
                        /* Timed out. */
-                       printk (KERN_DEBUG "DMA write timed out\n");
+                       printk(KERN_DEBUG "DMA write timed out\n");
                        break;
                }
                /* Is serviceIntr set? */
-               if (!(inb (ECONTROL (port)) & (1<<2))) {
+               if (!(inb(ECONTROL(port)) & (1<<2))) {
                        cond_resched();
 
                        goto false_alarm;
@@ -705,14 +713,15 @@ dump_parport_state ("enter fifo_write_block_dma", port);
 
                /* Anyone else waiting for the port? */
                if (port->waithead) {
-                       printk (KERN_DEBUG "Somebody wants the port\n");
+                       printk(KERN_DEBUG "Somebody wants the port\n");
                        break;
                }
 
                /* update for possible DMA residue ! */
                buf  -= count;
                left += count;
-               if (dma_handle) dma_addr -= count;
+               if (dma_handle)
+                       dma_addr -= count;
        }
 
        /* Maybe got here through break, so adjust for DMA residue! */
@@ -723,12 +732,12 @@ dump_parport_state ("enter fifo_write_block_dma", port);
        release_dma_lock(dmaflag);
 
        /* Turn off DMA mode */
-       frob_econtrol (port, 1<<3, 0);
+       frob_econtrol(port, 1<<3, 0);
 
        if (dma_handle)
                dma_unmap_single(dev, dma_handle, length, DMA_TO_DEVICE);
 
-dump_parport_state ("leave fifo_write_block_dma", port);
+       dump_parport_state("leave fifo_write_block_dma", port);
        return length - left;
 }
 #endif
@@ -738,13 +747,13 @@ static inline size_t parport_pc_fifo_write_block(struct parport *port,
 {
 #ifdef HAS_DMA
        if (port->dma != PARPORT_DMA_NONE)
-               return parport_pc_fifo_write_block_dma (port, buf, length);
+               return parport_pc_fifo_write_block_dma(port, buf, length);
 #endif
-       return parport_pc_fifo_write_block_pio (port, buf, length);
+       return parport_pc_fifo_write_block_pio(port, buf, length);
 }
 
 /* Parallel Port FIFO mode (ECP chipsets) */
-static size_t parport_pc_compat_write_block_pio (struct parport *port,
+static size_t parport_pc_compat_write_block_pio(struct parport *port,
                                                 const void *buf, size_t length,
                                                 int flags)
 {
@@ -756,14 +765,16 @@ static size_t parport_pc_compat_write_block_pio (struct parport *port,
        /* Special case: a timeout of zero means we cannot call schedule().
         * Also if O_NONBLOCK is set then use the default implementation. */
        if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
-               return parport_ieee1284_write_compat (port, buf,
+               return parport_ieee1284_write_compat(port, buf,
                                                      length, flags);
 
        /* Set up parallel port FIFO mode.*/
-       parport_pc_data_forward (port); /* Must be in PS2 mode */
-       parport_pc_frob_control (port, PARPORT_CONTROL_STROBE, 0);
-       r = change_mode (port, ECR_PPF); /* Parallel port FIFO */
-       if (r)  printk (KERN_DEBUG "%s: Warning change_mode ECR_PPF failed\n", port->name);
+       parport_pc_data_forward(port); /* Must be in PS2 mode */
+       parport_pc_frob_control(port, PARPORT_CONTROL_STROBE, 0);
+       r = change_mode(port, ECR_PPF); /* Parallel port FIFO */
+       if (r)
+               printk(KERN_DEBUG "%s: Warning change_mode ECR_PPF failed\n",
+                                                               port->name);
 
        port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
 
@@ -775,40 +786,39 @@ static size_t parport_pc_compat_write_block_pio (struct parport *port,
         * the FIFO is empty, so allow 4 seconds for each position
         * in the fifo.
         */
-        expire = jiffies + (priv->fifo_depth * HZ * 4);
+       expire = jiffies + (priv->fifo_depth * HZ * 4);
        do {
                /* Wait for the FIFO to empty */
-               r = change_mode (port, ECR_PS2);
-               if (r != -EBUSY) {
+               r = change_mode(port, ECR_PS2);
+               if (r != -EBUSY)
                        break;
-               }
-       } while (time_before (jiffies, expire));
+       } while (time_before(jiffies, expire));
        if (r == -EBUSY) {
 
-               printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
+               printk(KERN_DEBUG "%s: FIFO is stuck\n", port->name);
 
                /* Prevent further data transfer. */
-               frob_set_mode (port, ECR_TST);
+               frob_set_mode(port, ECR_TST);
 
                /* Adjust for the contents of the FIFO. */
                for (written -= priv->fifo_depth; ; written++) {
-                       if (inb (ECONTROL (port)) & 0x2) {
+                       if (inb(ECONTROL(port)) & 0x2) {
                                /* Full up. */
                                break;
                        }
-                       outb (0, FIFO (port));
+                       outb(0, FIFO(port));
                }
 
                /* Reset the FIFO and return to PS2 mode. */
-               frob_set_mode (port, ECR_PS2);
+               frob_set_mode(port, ECR_PS2);
        }
 
-       r = parport_wait_peripheral (port,
+       r = parport_wait_peripheral(port,
                                     PARPORT_STATUS_BUSY,
                                     PARPORT_STATUS_BUSY);
        if (r)
-               printk (KERN_DEBUG
-                       "%s: BUSY timeout (%d) in compat_write_block_pio\n", 
+               printk(KERN_DEBUG
+                       "%s: BUSY timeout (%d) in compat_write_block_pio\n",
                        port->name, r);
 
        port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
@@ -818,7 +828,7 @@ static size_t parport_pc_compat_write_block_pio (struct parport *port,
 
 /* ECP */
 #ifdef CONFIG_PARPORT_1284
-static size_t parport_pc_ecp_write_block_pio (struct parport *port,
+static size_t parport_pc_ecp_write_block_pio(struct parport *port,
                                              const void *buf, size_t length,
                                              int flags)
 {
@@ -830,36 +840,38 @@ static size_t parport_pc_ecp_write_block_pio (struct parport *port,
        /* Special case: a timeout of zero means we cannot call schedule().
         * Also if O_NONBLOCK is set then use the default implementation. */
        if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
-               return parport_ieee1284_ecp_write_data (port, buf,
+               return parport_ieee1284_ecp_write_data(port, buf,
                                                        length, flags);
 
        /* Switch to forward mode if necessary. */
        if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
                /* Event 47: Set nInit high. */
-               parport_frob_control (port,
+               parport_frob_control(port,
                                      PARPORT_CONTROL_INIT
                                      | PARPORT_CONTROL_AUTOFD,
                                      PARPORT_CONTROL_INIT
                                      | PARPORT_CONTROL_AUTOFD);
 
                /* Event 49: PError goes high. */
-               r = parport_wait_peripheral (port,
+               r = parport_wait_peripheral(port,
                                             PARPORT_STATUS_PAPEROUT,
                                             PARPORT_STATUS_PAPEROUT);
                if (r) {
-                       printk (KERN_DEBUG "%s: PError timeout (%d) "
+                       printk(KERN_DEBUG "%s: PError timeout (%d) "
                                "in ecp_write_block_pio\n", port->name, r);
                }
        }
 
        /* Set up ECP parallel port mode.*/
-       parport_pc_data_forward (port); /* Must be in PS2 mode */
-       parport_pc_frob_control (port,
+       parport_pc_data_forward(port); /* Must be in PS2 mode */
+       parport_pc_frob_control(port,
                                 PARPORT_CONTROL_STROBE |
                                 PARPORT_CONTROL_AUTOFD,
                                 0);
-       r = change_mode (port, ECR_ECP); /* ECP FIFO */
-       if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name);
+       r = change_mode(port, ECR_ECP); /* ECP FIFO */
+       if (r)
+               printk(KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n",
+                                                               port->name);
        port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
 
        /* Write the data to the FIFO. */
@@ -873,55 +885,54 @@ static size_t parport_pc_ecp_write_block_pio (struct parport *port,
        expire = jiffies + (priv->fifo_depth * (HZ * 4));
        do {
                /* Wait for the FIFO to empty */
-               r = change_mode (port, ECR_PS2);
-               if (r != -EBUSY) {
+               r = change_mode(port, ECR_PS2);
+               if (r != -EBUSY)
                        break;
-               }
-       } while (time_before (jiffies, expire));
+       } while (time_before(jiffies, expire));
        if (r == -EBUSY) {
 
-               printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
+               printk(KERN_DEBUG "%s: FIFO is stuck\n", port->name);
 
                /* Prevent further data transfer. */
-               frob_set_mode (port, ECR_TST);
+               frob_set_mode(port, ECR_TST);
 
                /* Adjust for the contents of the FIFO. */
                for (written -= priv->fifo_depth; ; written++) {
-                       if (inb (ECONTROL (port)) & 0x2) {
+                       if (inb(ECONTROL(port)) & 0x2) {
                                /* Full up. */
                                break;
                        }
-                       outb (0, FIFO (port));
+                       outb(0, FIFO(port));
                }
 
                /* Reset the FIFO and return to PS2 mode. */
-               frob_set_mode (port, ECR_PS2);
+               frob_set_mode(port, ECR_PS2);
 
                /* Host transfer recovery. */
-               parport_pc_data_reverse (port); /* Must be in PS2 mode */
-               udelay (5);
-               parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
-               r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+               parport_pc_data_reverse(port); /* Must be in PS2 mode */
+               udelay(5);
+               parport_frob_control(port, PARPORT_CONTROL_INIT, 0);
+               r = parport_wait_peripheral(port, PARPORT_STATUS_PAPEROUT, 0);
                if (r)
-                       printk (KERN_DEBUG "%s: PE,1 timeout (%d) "
+                       printk(KERN_DEBUG "%s: PE,1 timeout (%d) "
                                "in ecp_write_block_pio\n", port->name, r);
 
-               parport_frob_control (port,
+               parport_frob_control(port,
                                      PARPORT_CONTROL_INIT,
                                      PARPORT_CONTROL_INIT);
-               r = parport_wait_peripheral (port,
+               r = parport_wait_peripheral(port,
                                             PARPORT_STATUS_PAPEROUT,
                                             PARPORT_STATUS_PAPEROUT);
-                if (r)
-                        printk (KERN_DEBUG "%s: PE,2 timeout (%d) "
+               if (r)
+                       printk(KERN_DEBUG "%s: PE,2 timeout (%d) "
                                "in ecp_write_block_pio\n", port->name, r);
        }
 
-       r = parport_wait_peripheral (port,
-                                    PARPORT_STATUS_BUSY, 
+       r = parport_wait_peripheral(port,
+                                    PARPORT_STATUS_BUSY,
                                     PARPORT_STATUS_BUSY);
-       if(r)
-               printk (KERN_DEBUG
+       if (r)
+               printk(KERN_DEBUG
                        "%s: BUSY timeout (%d) in ecp_write_block_pio\n",
                        port->name, r);
 
@@ -931,7 +942,7 @@ static size_t parport_pc_ecp_write_block_pio (struct parport *port,
 }
 
 #if 0
-static size_t parport_pc_ecp_read_block_pio (struct parport *port,
+static size_t parport_pc_ecp_read_block_pio(struct parport *port,
                                             void *buf, size_t length,
                                             int flags)
 {
@@ -944,13 +955,13 @@ static size_t parport_pc_ecp_read_block_pio (struct parport *port,
        char *bufp = buf;
 
        port = port->physport;
-DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n");
-dump_parport_state ("enter fcn", port);
+       DPRINTK(KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n");
+       dump_parport_state("enter fcn", port);
 
        /* Special case: a timeout of zero means we cannot call schedule().
         * Also if O_NONBLOCK is set then use the default implementation. */
        if (port->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
-               return parport_ieee1284_ecp_read_data (port, buf,
+               return parport_ieee1284_ecp_read_data(port, buf,
                                                       length, flags);
 
        if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) {
@@ -966,173 +977,178 @@ dump_parport_state ("enter fcn", port);
         * go through software emulation.  Otherwise we may have to throw
         * away data. */
        if (length < fifofull)
-               return parport_ieee1284_ecp_read_data (port, buf,
+               return parport_ieee1284_ecp_read_data(port, buf,
                                                       length, flags);
 
        if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) {
                /* change to reverse-idle phase (must be in forward-idle) */
 
                /* Event 38: Set nAutoFd low (also make sure nStrobe is high) */
-               parport_frob_control (port,
+               parport_frob_control(port,
                                      PARPORT_CONTROL_AUTOFD
                                      | PARPORT_CONTROL_STROBE,
                                      PARPORT_CONTROL_AUTOFD);
-               parport_pc_data_reverse (port); /* Must be in PS2 mode */
-               udelay (5);
+               parport_pc_data_reverse(port); /* Must be in PS2 mode */
+               udelay(5);
                /* Event 39: Set nInit low to initiate bus reversal */
-               parport_frob_control (port,
+               parport_frob_control(port,
                                      PARPORT_CONTROL_INIT,
                                      0);
                /* Event 40: Wait for  nAckReverse (PError) to go low */
-               r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
-                if (r) {
-                        printk (KERN_DEBUG "%s: PE timeout Event 40 (%d) "
+               r = parport_wait_peripheral(port, PARPORT_STATUS_PAPEROUT, 0);
+               if (r) {
+                       printk(KERN_DEBUG "%s: PE timeout Event 40 (%d) "
                                "in ecp_read_block_pio\n", port->name, r);
                        return 0;
                }
        }
 
        /* Set up ECP FIFO mode.*/
-/*     parport_pc_frob_control (port,
+/*     parport_pc_frob_control(port,
                                 PARPORT_CONTROL_STROBE |
                                 PARPORT_CONTROL_AUTOFD,
                                 PARPORT_CONTROL_AUTOFD); */
-       r = change_mode (port, ECR_ECP); /* ECP FIFO */
-       if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name);
+       r = change_mode(port, ECR_ECP); /* ECP FIFO */
+       if (r)
+               printk(KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n",
+                                                               port->name);
 
        port->ieee1284.phase = IEEE1284_PH_REV_DATA;
 
        /* the first byte must be collected manually */
-dump_parport_state ("pre 43", port);
+       dump_parport_state("pre 43", port);
        /* Event 43: Wait for nAck to go low */
-       r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0);
+       r = parport_wait_peripheral(port, PARPORT_STATUS_ACK, 0);
        if (r) {
                /* timed out while reading -- no data */
-               printk (KERN_DEBUG "PIO read timed out (initial byte)\n");
+               printk(KERN_DEBUG "PIO read timed out (initial byte)\n");
                goto out_no_data;
        }
        /* read byte */
-       *bufp++ = inb (DATA (port));
+       *bufp++ = inb(DATA(port));
        left--;
-dump_parport_state ("43-44", port);
+       dump_parport_state("43-44", port);
        /* Event 44: nAutoFd (HostAck) goes high to acknowledge */
-       parport_pc_frob_control (port,
+       parport_pc_frob_control(port,
                                 PARPORT_CONTROL_AUTOFD,
                                 0);
-dump_parport_state ("pre 45", port);
+       dump_parport_state("pre 45", port);
        /* Event 45: Wait for nAck to go high */
-/*     r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK); */
-dump_parport_state ("post 45", port);
-r = 0;
+       /* r = parport_wait_peripheral(port, PARPORT_STATUS_ACK,
+                                               PARPORT_STATUS_ACK); */
+       dump_parport_state("post 45", port);
+       r = 0;
        if (r) {
                /* timed out while waiting for peripheral to respond to ack */
-               printk (KERN_DEBUG "ECP PIO read timed out (waiting for nAck)\n");
+               printk(KERN_DEBUG "ECP PIO read timed out (waiting for nAck)\n");
 
                /* keep hold of the byte we've got already */
                goto out_no_data;
        }
        /* Event 46: nAutoFd (HostAck) goes low to accept more data */
-       parport_pc_frob_control (port,
+       parport_pc_frob_control(port,
                                 PARPORT_CONTROL_AUTOFD,
                                 PARPORT_CONTROL_AUTOFD);
 
 
-dump_parport_state ("rev idle", port);
+       dump_parport_state("rev idle", port);
        /* Do the transfer. */
        while (left > fifofull) {
                int ret;
                unsigned long expire = jiffies + port->cad->timeout;
-               unsigned char ecrval = inb (ECONTROL (port));
+               unsigned char ecrval = inb(ECONTROL(port));
 
-               if (need_resched() && time_before (jiffies, expire))
+               if (need_resched() && time_before(jiffies, expire))
                        /* Can't yield the port. */
-                       schedule ();
+                       schedule();
 
                /* At this point, the FIFO may already be full. In
-                 * that case ECP is already holding back the
-                 * peripheral (assuming proper design) with a delayed
-                 * handshake.  Work fast to avoid a peripheral
-                 * timeout.  */
+                * that case ECP is already holding back the
+                * peripheral (assuming proper design) with a delayed
+                * handshake.  Work fast to avoid a peripheral
+                * timeout.  */
 
                if (ecrval & 0x01) {
                        /* FIFO is empty. Wait for interrupt. */
-dump_parport_state ("FIFO empty", port);
+                       dump_parport_state("FIFO empty", port);
 
                        /* Anyone else waiting for the port? */
                        if (port->waithead) {
-                               printk (KERN_DEBUG "Somebody wants the port\n");
+                               printk(KERN_DEBUG "Somebody wants the port\n");
                                break;
                        }
 
                        /* Clear serviceIntr */
-                       ECR_WRITE (port, ecrval & ~(1<<2));
-               false_alarm:
-dump_parport_state ("waiting", port);
-                       ret = parport_wait_event (port, HZ);
-DPRINTK (KERN_DEBUG "parport_wait_event returned %d\n", ret);
+                       ECR_WRITE(port, ecrval & ~(1<<2));
+false_alarm:
+                       dump_parport_state("waiting", port);
+                       ret = parport_wait_event(port, HZ);
+                       DPRINTK(KERN_DEBUG "parport_wait_event returned %d\n",
+                                                                       ret);
                        if (ret < 0)
                                break;
                        ret = 0;
-                       if (!time_before (jiffies, expire)) {
+                       if (!time_before(jiffies, expire)) {
                                /* Timed out. */
-dump_parport_state ("timeout", port);
-                               printk (KERN_DEBUG "PIO read timed out\n");
+                               dump_parport_state("timeout", port);
+                               printk(KERN_DEBUG "PIO read timed out\n");
                                break;
                        }
-                       ecrval = inb (ECONTROL (port));
+                       ecrval = inb(ECONTROL(port));
                        if (!(ecrval & (1<<2))) {
                                if (need_resched() &&
-                                   time_before (jiffies, expire)) {
-                                       schedule ();
+                                   time_before(jiffies, expire)) {
+                                       schedule();
                                }
                                goto false_alarm;
                        }
 
                        /* Depending on how the FIFO threshold was
-                         * set, how long interrupt service took, and
-                         * how fast the peripheral is, we might be
-                         * lucky and have a just filled FIFO. */
+                        * set, how long interrupt service took, and
+                        * how fast the peripheral is, we might be
+                        * lucky and have a just filled FIFO. */
                        continue;
                }
 
                if (ecrval & 0x02) {
                        /* FIFO is full. */
-dump_parport_state ("FIFO full", port);
-                       insb (fifo, bufp, fifo_depth);
+                       dump_parport_state("FIFO full", port);
+                       insb(fifo, bufp, fifo_depth);
                        bufp += fifo_depth;
                        left -= fifo_depth;
                        continue;
                }
 
-DPRINTK (KERN_DEBUG "*** ecp_read_block_pio: reading one byte from the FIFO\n");
+               DPRINTK(KERN_DEBUG
+                 "*** ecp_read_block_pio: reading one byte from the FIFO\n");
 
                /* FIFO not filled.  We will cycle this loop for a while
-                 * and either the peripheral will fill it faster,
-                 * tripping a fast empty with insb, or we empty it. */
-               *bufp++ = inb (fifo);
+                * and either the peripheral will fill it faster,
+                * tripping a fast empty with insb, or we empty it. */
+               *bufp++ = inb(fifo);
                left--;
        }
 
        /* scoop up anything left in the FIFO */
-       while (left && !(inb (ECONTROL (port) & 0x01))) {
-               *bufp++ = inb (fifo);
+       while (left && !(inb(ECONTROL(port) & 0x01))) {
+               *bufp++ = inb(fifo);
                left--;
        }
 
        port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
-dump_parport_state ("rev idle2", port);
+       dump_parport_state("rev idle2", port);
 
 out_no_data:
 
        /* Go to forward idle mode to shut the peripheral up (event 47). */
-       parport_frob_control (port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
+       parport_frob_control(port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
 
        /* event 49: PError goes high */
-       r = parport_wait_peripheral (port,
+       r = parport_wait_peripheral(port,
                                     PARPORT_STATUS_PAPEROUT,
                                     PARPORT_STATUS_PAPEROUT);
        if (r) {
-               printk (KERN_DEBUG
+               printk(KERN_DEBUG
                        "%s: PE timeout FWDIDLE (%d) in ecp_read_block_pio\n",
                        port->name, r);
        }
@@ -1141,14 +1157,14 @@ out_no_data:
 
        /* Finish up. */
        {
-               int lost = get_fifo_residue (port);
+               int lost = get_fifo_residue(port);
                if (lost)
                        /* Shouldn't happen with compliant peripherals. */
-                       printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n",
+                       printk(KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n",
                                port->name, lost);
        }
 
-dump_parport_state ("fwd idle", port);
+       dump_parport_state("fwd idle", port);
        return length - left;
 }
 #endif  /*  0  */
@@ -1164,8 +1180,7 @@ dump_parport_state ("fwd idle", port);
 
 /* GCC is not inlining extern inline function later overwriten to non-inline,
    so we use outlined_ variants here.  */
-static const struct parport_operations parport_pc_ops =
-{
+static const struct parport_operations parport_pc_ops = {
        .write_data     = parport_pc_write_data,
        .read_data      = parport_pc_read_data,
 
@@ -1202,88 +1217,107 @@ static const struct parport_operations parport_pc_ops =
 };
 
 #ifdef CONFIG_PARPORT_PC_SUPERIO
+
+static struct superio_struct *find_free_superio(void)
+{
+       int i;
+       for (i = 0; i < NR_SUPERIOS; i++)
+               if (superios[i].io == 0)
+                       return &superios[i];
+       return NULL;
+}
+
+
 /* Super-IO chipset detection, Winbond, SMSC */
 static void __devinit show_parconfig_smsc37c669(int io, int key)
 {
-       int cr1,cr4,cra,cr23,cr26,cr27,i=0;
-       static const char *const modes[]={
+       int cr1, cr4, cra, cr23, cr26, cr27;
+       struct superio_struct *s;
+
+       static const char *const modes[] = {
                "SPP and Bidirectional (PS/2)",
                "EPP and SPP",
                "ECP",
                "ECP and EPP" };
 
-       outb(key,io);
-       outb(key,io);
-       outb(1,io);
-       cr1=inb(io+1);
-       outb(4,io);
-       cr4=inb(io+1);
-       outb(0x0a,io);
-       cra=inb(io+1);
-       outb(0x23,io);
-       cr23=inb(io+1);
-       outb(0x26,io);
-       cr26=inb(io+1);
-       outb(0x27,io);
-       cr27=inb(io+1);
-       outb(0xaa,io);
+       outb(key, io);
+       outb(key, io);
+       outb(1, io);
+       cr1 = inb(io + 1);
+       outb(4, io);
+       cr4 = inb(io + 1);
+       outb(0x0a, io);
+       cra = inb(io + 1);
+       outb(0x23, io);
+       cr23 = inb(io + 1);
+       outb(0x26, io);
+       cr26 = inb(io + 1);
+       outb(0x27, io);
+       cr27 = inb(io + 1);
+       outb(0xaa, io);
 
        if (verbose_probing) {
-               printk (KERN_INFO "SMSC 37c669 LPT Config: cr_1=0x%02x, 4=0x%02x, "
+               printk(KERN_INFO
+                       "SMSC 37c669 LPT Config: cr_1=0x%02x, 4=0x%02x, "
                        "A=0x%2x, 23=0x%02x, 26=0x%02x, 27=0x%02x\n",
-                       cr1,cr4,cra,cr23,cr26,cr27);
-               
+                       cr1, cr4, cra, cr23, cr26, cr27);
+
                /* The documentation calls DMA and IRQ-Lines by letters, so
                   the board maker can/will wire them
                   appropriately/randomly...  G=reserved H=IDE-irq, */
-               printk (KERN_INFO "SMSC LPT Config: io=0x%04x, irq=%c, dma=%c, "
-                       "fifo threshold=%d\n", cr23*4,
-                       (cr27 &0x0f) ? 'A'-1+(cr27 &0x0f): '-',
-                       (cr26 &0x0f) ? 'A'-1+(cr26 &0x0f): '-', cra & 0x0f);
+               printk(KERN_INFO
+       "SMSC LPT Config: io=0x%04x, irq=%c, dma=%c, fifo threshold=%d\n",
+                               cr23 * 4,
+                               (cr27 & 0x0f) ? 'A' - 1 + (cr27 & 0x0f) : '-',
+                               (cr26 & 0x0f) ? 'A' - 1 + (cr26 & 0x0f) : '-',
+                               cra & 0x0f);
                printk(KERN_INFO "SMSC LPT Config: enabled=%s power=%s\n",
-                      (cr23*4 >=0x100) ?"yes":"no", (cr1 & 4) ? "yes" : "no");
-               printk(KERN_INFO "SMSC LPT Config: Port mode=%s, EPP version =%s\n",
-                      (cr1 & 0x08 ) ? "Standard mode only (SPP)" : modes[cr4 & 0x03], 
-                      (cr4 & 0x40) ? "1.7" : "1.9");
+                      (cr23 * 4 >= 0x100) ? "yes" : "no",
+                      (cr1 & 4) ? "yes" : "no");
+               printk(KERN_INFO
+                       "SMSC LPT Config: Port mode=%s, EPP version =%s\n",
+                               (cr1 & 0x08) ? "Standard mode only (SPP)"
+                                             : modes[cr4 & 0x03],
+                               (cr4 & 0x40) ? "1.7" : "1.9");
        }
-               
+
        /* Heuristics !  BIOS setup for this mainboard device limits
           the choices to standard settings, i.e. io-address and IRQ
           are related, however DMA can be 1 or 3, assume DMA_A=DMA1,
           DMA_C=DMA3 (this is true e.g. for TYAN 1564D Tomcat IV) */
-       if(cr23*4 >=0x100) { /* if active */
-               while((superios[i].io!= 0) && (i<NR_SUPERIOS))
-                       i++;
-               if(i==NR_SUPERIOS)
+       if (cr23 * 4 >= 0x100) { /* if active */
+               s = find_free_superio();
+               if (s == NULL)
                        printk(KERN_INFO "Super-IO: too many chips!\n");
                else {
                        int d;
-                       switch (cr23*4) {
-                               case 0x3bc:
-                                       superios[i].io = 0x3bc;
-                                       superios[i].irq = 7;
-                                       break;
-                               case 0x378:
-                                       superios[i].io = 0x378;
-                                       superios[i].irq = 7;
-                                       break;
-                               case 0x278:
-                                       superios[i].io = 0x278;
-                                       superios[i].irq = 5;
+                       switch (cr23 * 4) {
+                       case 0x3bc:
+                               s->io = 0x3bc;
+                               s->irq = 7;
+                               break;
+                       case 0x378:
+                               s->io = 0x378;
+                               s->irq = 7;
+                               break;
+                       case 0x278:
+                               s->io = 0x278;
+                               s->irq = 5;
                        }
-                       d=(cr26 &0x0f);
-                       if((d==1) || (d==3)) 
-                               superios[i].dma= d;
+                       d = (cr26 & 0x0f);
+                       if (d == 1 || d == 3)
+                               s->dma = d;
                        else
-                               superios[i].dma= PARPORT_DMA_NONE;
+                               s->dma = PARPORT_DMA_NONE;
                }
-       }
+       }
 }
 
 
 static void __devinit show_parconfig_winbond(int io, int key)
 {
-       int cr30,cr60,cr61,cr70,cr74,crf0,i=0;
+       int cr30, cr60, cr61, cr70, cr74, crf0;
+       struct superio_struct *s;
        static const char *const modes[] = {
                "Standard (SPP) and Bidirectional(PS/2)", /* 0 */
                "EPP-1.9 and SPP",
@@ -1296,110 +1330,134 @@ static void __devinit show_parconfig_winbond(int io, int key)
        static char *const irqtypes[] = {
                "pulsed low, high-Z",
                "follows nACK" };
-               
+
        /* The registers are called compatible-PnP because the
-           register layout is modelled after ISA-PnP, the access
-           method is just another ... */
-       outb(key,io);
-       outb(key,io);
-       outb(0x07,io);   /* Register 7: Select Logical Device */
-       outb(0x01,io+1); /* LD1 is Parallel Port */
-       outb(0x30,io);
-       cr30=inb(io+1);
-       outb(0x60,io);
-       cr60=inb(io+1);
-       outb(0x61,io);
-       cr61=inb(io+1);
-       outb(0x70,io);
-       cr70=inb(io+1);
-       outb(0x74,io);
-       cr74=inb(io+1);
-       outb(0xf0,io);
-       crf0=inb(io+1);
-       outb(0xaa,io);
+          register layout is modelled after ISA-PnP, the access
+          method is just another ... */
+       outb(key, io);
+       outb(key, io);
+       outb(0x07, io);   /* Register 7: Select Logical Device */
+       outb(0x01, io + 1); /* LD1 is Parallel Port */
+       outb(0x30, io);
+       cr30 = inb(io + 1);
+       outb(0x60, io);
+       cr60 = inb(io + 1);
+       outb(0x61, io);
+       cr61 = inb(io + 1);
+       outb(0x70, io);
+       cr70 = inb(io + 1);
+       outb(0x74, io);
+       cr74 = inb(io + 1);
+       outb(0xf0, io);
+       crf0 = inb(io + 1);
+       outb(0xaa, io);
 
        if (verbose_probing) {
-               printk(KERN_INFO "Winbond LPT Config: cr_30=%02x 60,61=%02x%02x "
-                      "70=%02x 74=%02x, f0=%02x\n", cr30,cr60,cr61,cr70,cr74,crf0);
-               printk(KERN_INFO "Winbond LPT Config: active=%s, io=0x%02x%02x irq=%d, ", 
-                      (cr30 & 0x01) ? "yes":"no", cr60,cr61,cr70&0x0f );
+               printk(KERN_INFO
+    "Winbond LPT Config: cr_30=%02x 60,61=%02x%02x 70=%02x 74=%02x, f0=%02x\n",
+                                       cr30, cr60, cr61, cr70, cr74, crf0);
+               printk(KERN_INFO "Winbond LPT Config: active=%s, io=0x%02x%02x irq=%d, ",
+                      (cr30 & 0x01) ? "yes" : "no", cr60, cr61, cr70 & 0x0f);
                if ((cr74 & 0x07) > 3)
                        printk("dma=none\n");
                else
-                       printk("dma=%d\n",cr74 & 0x07);
-               printk(KERN_INFO "Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n",
-                      irqtypes[crf0>>7], (crf0>>3)&0x0f);
-               printk(KERN_INFO "Winbond LPT Config: Port mode=%s\n", modes[crf0 & 0x07]);
+                       printk("dma=%d\n", cr74 & 0x07);
+               printk(KERN_INFO
+                   "Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n",
+                                       irqtypes[crf0>>7], (crf0>>3)&0x0f);
+               printk(KERN_INFO "Winbond LPT Config: Port mode=%s\n",
+                                       modes[crf0 & 0x07]);
        }
 
-       if(cr30 & 0x01) { /* the settings can be interrogated later ... */
-               while((superios[i].io!= 0) && (i<NR_SUPERIOS))
-                       i++;
-               if(i==NR_SUPERIOS) 
+       if (cr30 & 0x01) { /* the settings can be interrogated later ... */
+               s = find_free_superio();
+               if (s == NULL)
                        printk(KERN_INFO "Super-IO: too many chips!\n");
                else {
-                       superios[i].io = (cr60<<8)|cr61;
-                       superios[i].irq = cr70&0x0f;
-                       superios[i].dma = (((cr74 & 0x07) > 3) ?
+                       s->io = (cr60 << 8) | cr61;
+                       s->irq = cr70 & 0x0f;
+                       s->dma = (((cr74 & 0x07) > 3) ?
                                           PARPORT_DMA_NONE : (cr74 & 0x07));
                }
        }
 }
 
-static void __devinit decode_winbond(int efer, int key, int devid, int devrev, int oldid)
+static void __devinit decode_winbond(int efer, int key, int devid,
+                                                       int devrev, int oldid)
 {
        const char *type = "unknown";
-       int id,progif=2;
+       int id, progif = 2;
 
        if (devid == devrev)
                /* simple heuristics, we happened to read some
-                   non-winbond register */
+                  non-winbond register */
                return;
 
-       id=(devid<<8) | devrev;
+       id = (devid << 8) | devrev;
 
        /* Values are from public data sheets pdf files, I can just
-           confirm 83977TF is correct :-) */
-       if      (id == 0x9771) type="83977F/AF";
-       else if (id == 0x9773) type="83977TF / SMSC 97w33x/97w34x";
-       else if (id == 0x9774) type="83977ATF";
-       else if ((id & ~0x0f) == 0x5270) type="83977CTF / SMSC 97w36x";
-       else if ((id & ~0x0f) == 0x52f0) type="83977EF / SMSC 97w35x";
-       else if ((id & ~0x0f) == 0x5210) type="83627";
-       else if ((id & ~0x0f) == 0x6010) type="83697HF";
-       else if ((oldid &0x0f ) == 0x0a) { type="83877F"; progif=1;}
-       else if ((oldid &0x0f ) == 0x0b) { type="83877AF"; progif=1;}
-       else if ((oldid &0x0f ) == 0x0c) { type="83877TF"; progif=1;}
-       else if ((oldid &0x0f ) == 0x0d) { type="83877ATF"; progif=1;}
-       else progif=0;
+          confirm 83977TF is correct :-) */
+       if (id == 0x9771)
+               type = "83977F/AF";
+       else if (id == 0x9773)
+               type = "83977TF / SMSC 97w33x/97w34x";
+       else if (id == 0x9774)
+               type = "83977ATF";
+       else if ((id & ~0x0f) == 0x5270)
+               type = "83977CTF / SMSC 97w36x";
+       else if ((id & ~0x0f) == 0x52f0)
+               type = "83977EF / SMSC 97w35x";
+       else if ((id & ~0x0f) == 0x5210)
+               type = "83627";
+       else if ((id & ~0x0f) == 0x6010)
+               type = "83697HF";
+       else if ((oldid & 0x0f) == 0x0a) {
+               type = "83877F";
+               progif = 1;
+       } else if ((oldid & 0x0f) == 0x0b) {
+               type = "83877AF";
+               progif = 1;
+       } else if ((oldid & 0x0f) == 0x0c) {
+               type = "83877TF";
+               progif = 1;
+       } else if ((oldid & 0x0f) == 0x0d) {
+               type = "83877ATF";
+               progif = 1;
+       } else
+               progif = 0;
 
        if (verbose_probing)
                printk(KERN_INFO "Winbond chip at EFER=0x%x key=0x%02x "
-                      "devid=%02x devrev=%02x oldid=%02x type=%s\n", 
+                      "devid=%02x devrev=%02x oldid=%02x type=%s\n",
                       efer, key, devid, devrev, oldid, type);
 
        if (progif == 2)
-               show_parconfig_winbond(efer,key);
+               show_parconfig_winbond(efer, key);
 }
 
 static void __devinit decode_smsc(int efer, int key, int devid, int devrev)
 {
-        const char *type = "unknown";
+       const char *type = "unknown";
        void (*func)(int io, int key);
-        int id;
+       int id;
 
-        if (devid == devrev)
+       if (devid == devrev)
                /* simple heuristics, we happened to read some
-                   non-smsc register */
+                  non-smsc register */
                return;
 
-       func=NULL;
-        id=(devid<<8) | devrev;
+       func = NULL;
+       id = (devid << 8) | devrev;
 
-       if      (id==0x0302) {type="37c669"; func=show_parconfig_smsc37c669;}
-       else if (id==0x6582) type="37c665IR";
-       else if (devid==0x65) type="37c665GT";
-       else if (devid==0x66) type="37c666GT";
+       if (id == 0x0302) {
+               type = "37c669";
+               func = show_parconfig_smsc37c669;
+       } else if (id == 0x6582)
+               type = "37c665IR";
+       else if (devid == 0x65)
+               type = "37c665GT";
+       else if (devid == 0x66)
+               type = "37c666GT";
 
        if (verbose_probing)
                printk(KERN_INFO "SMSC chip at EFER=0x%x "
@@ -1407,138 +1465,138 @@ static void __devinit decode_smsc(int efer, int key, int devid, int devrev)
                       efer, key, devid, devrev, type);
 
        if (func)
-               func(efer,key);
+               func(efer, key);
 }
 
 
 static void __devinit winbond_check(int io, int key)
 {
-       int devid,devrev,oldid,x_devid,x_devrev,x_oldid;
+       int devid, devrev, oldid, x_devid, x_devrev, x_oldid;
 
        if (!request_region(io, 3, __func__))
                return;
 
        /* First probe without key */
-       outb(0x20,io);
-       x_devid=inb(io+1);
-       outb(0x21,io);
-       x_devrev=inb(io+1);
-       outb(0x09,io);
-       x_oldid=inb(io+1);
-
-       outb(key,io);
-       outb(key,io);     /* Write Magic Sequence to EFER, extended
-                             funtion enable register */
-       outb(0x20,io);    /* Write EFIR, extended function index register */
-       devid=inb(io+1);  /* Read EFDR, extended function data register */
-       outb(0x21,io);
-       devrev=inb(io+1);
-       outb(0x09,io);
-       oldid=inb(io+1);
-       outb(0xaa,io);    /* Magic Seal */
+       outb(0x20, io);
+       x_devid = inb(io + 1);
+       outb(0x21, io);
+       x_devrev = inb(io + 1);
+       outb(0x09, io);
+       x_oldid = inb(io + 1);
+
+       outb(key, io);
+       outb(key, io);     /* Write Magic Sequence to EFER, extended
+                             funtion enable register */
+       outb(0x20, io);    /* Write EFIR, extended function index register */
+       devid = inb(io + 1);  /* Read EFDR, extended function data register */
+       outb(0x21, io);
+       devrev = inb(io + 1);
+       outb(0x09, io);
+       oldid = inb(io + 1);
+       outb(0xaa, io);    /* Magic Seal */
 
        if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid))
                goto out; /* protection against false positives */
 
-       decode_winbond(io,key,devid,devrev,oldid);
+       decode_winbond(io, key, devid, devrev, oldid);
 out:
        release_region(io, 3);
 }
 
-static void __devinit winbond_check2(int io,int key)
+static void __devinit winbond_check2(int io, int key)
 {
-        int devid,devrev,oldid,x_devid,x_devrev,x_oldid;
+       int devid, devrev, oldid, x_devid, x_devrev, x_oldid;
 
        if (!request_region(io, 3, __func__))
                return;
 
        /* First probe without the key */
-       outb(0x20,io+2);
-       x_devid=inb(io+2);
-       outb(0x21,io+1);
-       x_devrev=inb(io+2);
-       outb(0x09,io+1);
-       x_oldid=inb(io+2);
-
-        outb(key,io);     /* Write Magic Byte to EFER, extended
-                             funtion enable register */
-        outb(0x20,io+2);  /* Write EFIR, extended function index register */
-        devid=inb(io+2);  /* Read EFDR, extended function data register */
-        outb(0x21,io+1);
-        devrev=inb(io+2);
-        outb(0x09,io+1);
-        oldid=inb(io+2);
-        outb(0xaa,io);    /* Magic Seal */
-
-       if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid))
+       outb(0x20, io + 2);
+       x_devid = inb(io + 2);
+       outb(0x21, io + 1);
+       x_devrev = inb(io + 2);
+       outb(0x09, io + 1);
+       x_oldid = inb(io + 2);
+
+       outb(key, io);     /* Write Magic Byte to EFER, extended
+                             funtion enable register */
+       outb(0x20, io + 2);  /* Write EFIR, extended function index register */
+       devid = inb(io + 2);  /* Read EFDR, extended function data register */
+       outb(0x21, io + 1);
+       devrev = inb(io + 2);
+       outb(0x09, io + 1);
+       oldid = inb(io + 2);
+       outb(0xaa, io);    /* Magic Seal */
+
+       if (x_devid == devid && x_devrev == devrev && x_oldid == oldid)
                goto out; /* protection against false positives */
 
-       decode_winbond(io,key,devid,devrev,oldid);
+       decode_winbond(io, key, devid, devrev, oldid);
 out:
        release_region(io, 3);
 }
 
 static void __devinit smsc_check(int io, int key)
 {
-        int id,rev,oldid,oldrev,x_id,x_rev,x_oldid,x_oldrev;
+       int id, rev, oldid, oldrev, x_id, x_rev, x_oldid, x_oldrev;
 
        if (!request_region(io, 3, __func__))
                return;
 
        /* First probe without the key */
-       outb(0x0d,io);
-       x_oldid=inb(io+1);
-       outb(0x0e,io);
-       x_oldrev=inb(io+1);
-       outb(0x20,io);
-       x_id=inb(io+1);
-       outb(0x21,io);
-       x_rev=inb(io+1);
-
-        outb(key,io);
-        outb(key,io);     /* Write Magic Sequence to EFER, extended
-                             funtion enable register */
-        outb(0x0d,io);    /* Write EFIR, extended function index register */
-        oldid=inb(io+1);  /* Read EFDR, extended function data register */
-        outb(0x0e,io);
-        oldrev=inb(io+1);
-       outb(0x20,io);
-       id=inb(io+1);
-       outb(0x21,io);
-       rev=inb(io+1);
-        outb(0xaa,io);    /* Magic Seal */
-
-       if ((x_id == id) && (x_oldrev == oldrev) &&
-           (x_oldid == oldid) && (x_rev == rev))
+       outb(0x0d, io);
+       x_oldid = inb(io + 1);
+       outb(0x0e, io);
+       x_oldrev = inb(io + 1);
+       outb(0x20, io);
+       x_id = inb(io + 1);
+       outb(0x21, io);
+       x_rev = inb(io + 1);
+
+       outb(key, io);
+       outb(key, io);     /* Write Magic Sequence to EFER, extended
+                             funtion enable register */
+       outb(0x0d, io);    /* Write EFIR, extended function index register */
+       oldid = inb(io + 1);  /* Read EFDR, extended function data register */
+       outb(0x0e, io);
+       oldrev = inb(io + 1);
+       outb(0x20, io);
+       id = inb(io + 1);
+       outb(0x21, io);
+       rev = inb(io + 1);
+       outb(0xaa, io);    /* Magic Seal */
+
+       if (x_id == id && x_oldrev == oldrev &&
+           x_oldid == oldid && x_rev == rev)
                goto out; /* protection against false positives */
 
-        decode_smsc(io,key,oldid,oldrev);
+       decode_smsc(io, key, oldid, oldrev);
 out:
        release_region(io, 3);
 }
 
 
-static void __devinit detect_and_report_winbond (void)
-{ 
+static void __devinit detect_and_report_winbond(void)
+{
        if (verbose_probing)
                printk(KERN_DEBUG "Winbond Super-IO detection, now testing ports 3F0,370,250,4E,2E ...\n");
-       winbond_check(0x3f0,0x87);
-       winbond_check(0x370,0x87);
-       winbond_check(0x2e ,0x87);
-       winbond_check(0x4e ,0x87);
-       winbond_check(0x3f0,0x86);
-       winbond_check2(0x250,0x88); 
-       winbond_check2(0x250,0x89);
+       winbond_check(0x3f0, 0x87);
+       winbond_check(0x370, 0x87);
+       winbond_check(0x2e , 0x87);
+       winbond_check(0x4e , 0x87);
+       winbond_check(0x3f0, 0x86);
+       winbond_check2(0x250, 0x88);
+       winbond_check2(0x250, 0x89);
 }
 
-static void __devinit detect_and_report_smsc (void)
+static void __devinit detect_and_report_smsc(void)
 {
        if (verbose_probing)
                printk(KERN_DEBUG "SMSC Super-IO detection, now testing Ports 2F0, 370 ...\n");
-       smsc_check(0x3f0,0x55);
-       smsc_check(0x370,0x55);
-       smsc_check(0x3f0,0x44);
-       smsc_check(0x370,0x44);
+       smsc_check(0x3f0, 0x55);
+       smsc_check(0x370, 0x55);
+       smsc_check(0x3f0, 0x44);
+       smsc_check(0x370, 0x44);
 }
 
 static void __devinit detect_and_report_it87(void)
@@ -1573,34 +1631,39 @@ static void __devinit detect_and_report_it87(void)
 }
 #endif /* CONFIG_PARPORT_PC_SUPERIO */
 
-static int get_superio_dma (struct parport *p)
+static struct superio_struct *find_superio(struct parport *p)
 {
-       int i=0;
-       while( (superios[i].io != p->base) && (i<NR_SUPERIOS))
-               i++;
-       if (i!=NR_SUPERIOS)
-               return superios[i].dma;
+       int i;
+       for (i = 0; i < NR_SUPERIOS; i++)
+               if (superios[i].io != p->base)
+                       return &superios[i];
+       return NULL;
+}
+
+static int get_superio_dma(struct parport *p)
+{
+       struct superio_struct *s = find_superio(p);
+       if (s)
+               return s->dma;
        return PARPORT_DMA_NONE;
 }
 
-static int get_superio_irq (struct parport *p)
+static int get_superio_irq(struct parport *p)
 {
-       int i=0;
-        while( (superios[i].io != p->base) && (i<NR_SUPERIOS))
-                i++;
-        if (i!=NR_SUPERIOS)
-                return superios[i].irq;
-        return PARPORT_IRQ_NONE;
+       struct superio_struct *s = find_superio(p);
+       if (s)
+               return s->irq;
+       return PARPORT_IRQ_NONE;
 }
-       
+
 
 /* --- Mode detection ------------------------------------- */
 
 /*
  * Checks for port existence, all ports support SPP MODE
- * Returns: 
+ * Returns:
  *         0           :  No parallel port at this address
- *  PARPORT_MODE_PCSPP :  SPP port detected 
+ *  PARPORT_MODE_PCSPP :  SPP port detected
  *                        (if the user specified an ioport himself,
  *                         this shall always be the case!)
  *
@@ -1610,7 +1673,7 @@ static int parport_SPP_supported(struct parport *pb)
        unsigned char r, w;
 
        /*
-        * first clear an eventually pending EPP timeout 
+        * first clear an eventually pending EPP timeout
         * I (sailer@ife.ee.ethz.ch) have an SMSC chipset
         * that does not even respond to SPP cycles if an EPP
         * timeout is pending
@@ -1619,19 +1682,19 @@ static int parport_SPP_supported(struct parport *pb)
 
        /* Do a simple read-write test to make sure the port exists. */
        w = 0xc;
-       outb (w, CONTROL (pb));
+       outb(w, CONTROL(pb));
 
        /* Is there a control register that we can read from?  Some
         * ports don't allow reads, so read_control just returns a
         * software copy. Some ports _do_ allow reads, so bypass the
         * software copy here.  In addition, some bits aren't
         * writable. */
-       r = inb (CONTROL (pb));
+       r = inb(CONTROL(pb));
        if ((r & 0xf) == w) {
                w = 0xe;
-               outb (w, CONTROL (pb));
-               r = inb (CONTROL (pb));
-               outb (0xc, CONTROL (pb));
+               outb(w, CONTROL(pb));
+               r = inb(CONTROL(pb));
+               outb(0xc, CONTROL(pb));
                if ((r & 0xf) == w)
                        return PARPORT_MODE_PCSPP;
        }
@@ -1639,18 +1702,18 @@ static int parport_SPP_supported(struct parport *pb)
        if (user_specified)
                /* That didn't work, but the user thinks there's a
                 * port here. */
-               printk (KERN_INFO "parport 0x%lx (WARNING): CTR: "
+               printk(KERN_INFO "parport 0x%lx (WARNING): CTR: "
                        "wrote 0x%02x, read 0x%02x\n", pb->base, w, r);
 
        /* Try the data register.  The data lines aren't tri-stated at
         * this stage, so we expect back what we wrote. */
        w = 0xaa;
-       parport_pc_write_data (pb, w);
-       r = parport_pc_read_data (pb);
+       parport_pc_write_data(pb, w);
+       r = parport_pc_read_data(pb);
        if (r == w) {
                w = 0x55;
-               parport_pc_write_data (pb, w);
-               r = parport_pc_read_data (pb);
+               parport_pc_write_data(pb, w);
+               r = parport_pc_read_data(pb);
                if (r == w)
                        return PARPORT_MODE_PCSPP;
        }
@@ -1658,9 +1721,9 @@ static int parport_SPP_supported(struct parport *pb)
        if (user_specified) {
                /* Didn't work, but the user is convinced this is the
                 * place. */
-               printk (KERN_INFO "parport 0x%lx (WARNING): DATA: "
+               printk(KERN_INFO "parport 0x%lx (WARNING): DATA: "
                        "wrote 0x%02x, read 0x%02x\n", pb->base, w, r);
-               printk (KERN_INFO "parport 0x%lx: You gave this address, "
+               printk(KERN_INFO "parport 0x%lx: You gave this address, "
                        "but there is probably no parallel port there!\n",
                        pb->base);
        }
@@ -1691,33 +1754,33 @@ static int parport_ECR_present(struct parport *pb)
        struct parport_pc_private *priv = pb->private_data;
        unsigned char r = 0xc;
 
-       outb (r, CONTROL (pb));
-       if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) {
-               outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */
+       outb(r, CONTROL(pb));
+       if ((inb(ECONTROL(pb)) & 0x3) == (r & 0x3)) {
+               outb(r ^ 0x2, CONTROL(pb)); /* Toggle bit 1 */
 
-               r = inb (CONTROL (pb));
-               if ((inb (ECONTROL (pb)) & 0x2) == (r & 0x2))
+               r = inb(CONTROL(pb));
+               if ((inb(ECONTROL(pb)) & 0x2) == (r & 0x2))
                        goto no_reg; /* Sure that no ECR register exists */
        }
-       
-       if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1)
+
+       if ((inb(ECONTROL(pb)) & 0x3) != 0x1)
                goto no_reg;
 
-       ECR_WRITE (pb, 0x34);
-       if (inb (ECONTROL (pb)) != 0x35)
+       ECR_WRITE(pb, 0x34);
+       if (inb(ECONTROL(pb)) != 0x35)
                goto no_reg;
 
        priv->ecr = 1;
-       outb (0xc, CONTROL (pb));
-       
+       outb(0xc, CONTROL(pb));
+
        /* Go to mode 000 */
-       frob_set_mode (pb, ECR_SPP);
+       frob_set_mode(pb, ECR_SPP);
 
        return 1;
 
  no_reg:
-       outb (0xc, CONTROL (pb));
-       return 0; 
+       outb(0xc, CONTROL(pb));
+       return 0;
 }
 
 #ifdef CONFIG_PARPORT_1284
@@ -1727,7 +1790,7 @@ static int parport_ECR_present(struct parport *pb)
  * allows us to read data from the data lines.  In theory we would get back
  * 0xff but any peripheral attached to the port may drag some or all of the
  * lines down to zero.  So if we get back anything that isn't the contents
- * of the data register we deem PS/2 support to be present. 
+ * of the data register we deem PS/2 support to be present.
  *
  * Some SPP ports have "half PS/2" ability - you can't turn off the line
  * drivers, but an external peripheral with sufficiently beefy drivers of
@@ -1735,26 +1798,28 @@ static int parport_ECR_present(struct parport *pb)
  * where they can then be read back as normal.  Ports with this property
  * and the right type of device attached are likely to fail the SPP test,
  * (as they will appear to have stuck bits) and so the fact that they might
- * be misdetected here is rather academic. 
+ * be misdetected here is rather academic.
  */
 
 static int parport_PS2_supported(struct parport *pb)
 {
        int ok = 0;
-  
+
        clear_epp_timeout(pb);
 
        /* try to tri-state the buffer */
-       parport_pc_data_reverse (pb);
-       
+       parport_pc_data_reverse(pb);
+
        parport_pc_write_data(pb, 0x55);
-       if (parport_pc_read_data(pb) != 0x55) ok++;
+       if (parport_pc_read_data(pb) != 0x55)
+               ok++;
 
        parport_pc_write_data(pb, 0xaa);
-       if (parport_pc_read_data(pb) != 0xaa) ok++;
+       if (parport_pc_read_data(pb) != 0xaa)
+               ok++;
 
        /* cancel input mode */
-       parport_pc_data_forward (pb);
+       parport_pc_data_forward(pb);
 
        if (ok) {
                pb->modes |= PARPORT_MODE_TRISTATE;
@@ -1773,68 +1838,68 @@ static int parport_ECP_supported(struct parport *pb)
        int config, configb;
        int pword;
        struct parport_pc_private *priv = pb->private_data;
-       /* Translate ECP intrLine to ISA irq value */   
-       static const int intrline[]= { 0, 7, 9, 10, 11, 14, 15, 5 }; 
+       /* Translate ECP intrLine to ISA irq value */
+       static const int intrline[] = { 0, 7, 9, 10, 11, 14, 15, 5 };
 
        /* If there is no ECR, we have no hope of supporting ECP. */
        if (!priv->ecr)
                return 0;
 
        /* Find out FIFO depth */
-       ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */
-       ECR_WRITE (pb, ECR_TST << 5); /* TEST FIFO */
-       for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02); i++)
-               outb (0xaa, FIFO (pb));
+       ECR_WRITE(pb, ECR_SPP << 5); /* Reset FIFO */
+       ECR_WRITE(pb, ECR_TST << 5); /* TEST FIFO */
+       for (i = 0; i < 1024 && !(inb(ECONTROL(pb)) & 0x02); i++)
+               outb(0xaa, FIFO(pb));
 
        /*
         * Using LGS chipset it uses ECR register, but
         * it doesn't support ECP or FIFO MODE
         */
        if (i == 1024) {
-               ECR_WRITE (pb, ECR_SPP << 5);
+               ECR_WRITE(pb, ECR_SPP << 5);
                return 0;
        }
 
        priv->fifo_depth = i;
        if (verbose_probing)
-               printk (KERN_DEBUG "0x%lx: FIFO is %d bytes\n", pb->base, i);
+               printk(KERN_DEBUG "0x%lx: FIFO is %d bytes\n", pb->base, i);
 
        /* Find out writeIntrThreshold */
-       frob_econtrol (pb, 1<<2, 1<<2);
-       frob_econtrol (pb, 1<<2, 0);
+       frob_econtrol(pb, 1<<2, 1<<2);
+       frob_econtrol(pb, 1<<2, 0);
        for (i = 1; i <= priv->fifo_depth; i++) {
-               inb (FIFO (pb));
-               udelay (50);
-               if (inb (ECONTROL (pb)) & (1<<2))
+               inb(FIFO(pb));
+               udelay(50);
+               if (inb(ECONTROL(pb)) & (1<<2))
                        break;
        }
 
        if (i <= priv->fifo_depth) {
                if (verbose_probing)
-                       printk (KERN_DEBUG "0x%lx: writeIntrThreshold is %d\n",
+                       printk(KERN_DEBUG "0x%lx: writeIntrThreshold is %d\n",
                                pb->base, i);
        } else
                /* Number of bytes we know we can write if we get an
-                   interrupt. */
+                  interrupt. */
                i = 0;
 
        priv->writeIntrThreshold = i;
 
        /* Find out readIntrThreshold */
-       frob_set_mode (pb, ECR_PS2); /* Reset FIFO and enable PS2 */
-       parport_pc_data_reverse (pb); /* Must be in PS2 mode */
-       frob_set_mode (pb, ECR_TST); /* Test FIFO */
-       frob_econtrol (pb, 1<<2, 1<<2);
-       frob_econtrol (pb, 1<<2, 0);
+       frob_set_mode(pb, ECR_PS2); /* Reset FIFO and enable PS2 */
+       parport_pc_data_reverse(pb); /* Must be in PS2 mode */
+       frob_set_mode(pb, ECR_TST); /* Test FIFO */
+       frob_econtrol(pb, 1<<2, 1<<2);
+       frob_econtrol(pb, 1<<2, 0);
        for (i = 1; i <= priv->fifo_depth; i++) {
-               outb (0xaa, FIFO (pb));
-               if (inb (ECONTROL (pb)) & (1<<2))
+               outb(0xaa, FIFO(pb));
+               if (inb(ECONTROL(pb)) & (1<<2))
                        break;
        }
 
        if (i <= priv->fifo_depth) {
                if (verbose_probing)
-                       printk (KERN_INFO "0x%lx: readIntrThreshold is %d\n",
+                       printk(KERN_INFO "0x%lx: readIntrThreshold is %d\n",
                                pb->base, i);
        } else
                /* Number of bytes we can read if we get an interrupt. */
@@ -1842,23 +1907,23 @@ static int parport_ECP_supported(struct parport *pb)
 
        priv->readIntrThreshold = i;
 
-       ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */
-       ECR_WRITE (pb, 0xf4); /* Configuration mode */
-       config = inb (CONFIGA (pb));
+       ECR_WRITE(pb, ECR_SPP << 5); /* Reset FIFO */
+       ECR_WRITE(pb, 0xf4); /* Configuration mode */
+       config = inb(CONFIGA(pb));
        pword = (config >> 4) & 0x7;
        switch (pword) {
        case 0:
                pword = 2;
-               printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
+               printk(KERN_WARNING "0x%lx: Unsupported pword size!\n",
                        pb->base);
                break;
        case 2:
                pword = 4;
-               printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
+               printk(KERN_WARNING "0x%lx: Unsupported pword size!\n",
                        pb->base);
                break;
        default:
-               printk (KERN_WARNING "0x%lx: Unknown implementation ID\n",
+               printk(KERN_WARNING "0x%lx: Unknown implementation ID\n",
                        pb->base);
                /* Assume 1 */
        case 1:
@@ -1867,28 +1932,29 @@ static int parport_ECP_supported(struct parport *pb)
        priv->pword = pword;
 
        if (verbose_probing) {
-               printk (KERN_DEBUG "0x%lx: PWord is %d bits\n", pb->base, 8 * pword);
-               
-               printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base,
+               printk(KERN_DEBUG "0x%lx: PWord is %d bits\n",
+                       pb->base, 8 * pword);
+
+               printk(KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base,
                        config & 0x80 ? "Level" : "Pulses");
 
-               configb = inb (CONFIGB (pb));
-               printk (KERN_DEBUG "0x%lx: ECP port cfgA=0x%02x cfgB=0x%02x\n",
+               configb = inb(CONFIGB(pb));
+               printk(KERN_DEBUG "0x%lx: ECP port cfgA=0x%02x cfgB=0x%02x\n",
                        pb->base, config, configb);
-               printk (KERN_DEBUG "0x%lx: ECP settings irq=", pb->base);
-               if ((configb >>3) & 0x07)
-                       printk("%d",intrline[(configb >>3) & 0x07]);
+               printk(KERN_DEBUG "0x%lx: ECP settings irq=", pb->base);
+               if ((configb >> 3) & 0x07)
+                       printk("%d", intrline[(configb >> 3) & 0x07]);
                else
                        printk("<none or set by other means>");
-               printk (" dma=");
-               if( (configb & 0x03 ) == 0x00)
+               printk(" dma=");
+               if ((configb & 0x03) == 0x00)
                        printk("<none or set by other means>\n");
                else
-                       printk("%d\n",configb & 0x07);
+                       printk("%d\n", configb & 0x07);
        }
 
        /* Go back to mode 000 */
-       frob_set_mode (pb, ECR_SPP);
+       frob_set_mode(pb, ECR_SPP);
 
        return 1;
 }
@@ -1903,10 +1969,10 @@ static int parport_ECPPS2_supported(struct parport *pb)
        if (!priv->ecr)
                return 0;
 
-       oecr = inb (ECONTROL (pb));
-       ECR_WRITE (pb, ECR_PS2 << 5);
+       oecr = inb(ECONTROL(pb));
+       ECR_WRITE(pb, ECR_PS2 << 5);
        result = parport_PS2_supported(pb);
-       ECR_WRITE (pb, oecr);
+       ECR_WRITE(pb, oecr);
        return result;
 }
 
@@ -1930,16 +1996,15 @@ static int parport_EPP_supported(struct parport *pb)
         */
 
        /* If EPP timeout bit clear then EPP available */
-       if (!clear_epp_timeout(pb)) {
+       if (!clear_epp_timeout(pb))
                return 0;  /* No way to clear timeout */
-       }
 
        /* Check for Intel bug. */
        if (priv->ecr) {
                unsigned char i;
                for (i = 0x00; i < 0x80; i += 0x20) {
-                       ECR_WRITE (pb, i);
-                       if (clear_epp_timeout (pb)) {
+                       ECR_WRITE(pb, i);
+                       if (clear_epp_timeout(pb)) {
                                /* Phony EPP in ECP. */
                                return 0;
                        }
@@ -1963,17 +2028,16 @@ static int parport_ECPEPP_supported(struct parport *pb)
        int result;
        unsigned char oecr;
 
-       if (!priv->ecr) {
+       if (!priv->ecr)
                return 0;
-       }
 
-       oecr = inb (ECONTROL (pb));
+       oecr = inb(ECONTROL(pb));
        /* Search for SMC style EPP+ECP mode */
-       ECR_WRITE (pb, 0x80);
-       outb (0x04, CONTROL (pb));
+       ECR_WRITE(pb, 0x80);
+       outb(0x04, CONTROL(pb));
        result = parport_EPP_supported(pb);
 
-       ECR_WRITE (pb, oecr);
+       ECR_WRITE(pb, oecr);
 
        if (result) {
                /* Set up access functions to use ECP+EPP hardware. */
@@ -1991,11 +2055,25 @@ static int parport_ECPEPP_supported(struct parport *pb)
 /* Don't bother probing for modes we know we won't use. */
 static int __devinit parport_PS2_supported(struct parport *pb) { return 0; }
 #ifdef CONFIG_PARPORT_PC_FIFO
-static int parport_ECP_supported(struct parport *pb) { return 0; }
+static int parport_ECP_supported(struct parport *pb)
+{
+       return 0;
+}
 #endif
-static int __devinit parport_EPP_supported(struct parport *pb) { return 0; }
-static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;}
-static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;}
+static int __devinit parport_EPP_supported(struct parport *pb)
+{
+       return 0;
+}
+
+static int __devinit parport_ECPEPP_supported(struct parport *pb)
+{
+       return 0;
+}
+
+static int __devinit parport_ECPPS2_supported(struct parport *pb)
+{
+       return 0;
+}
 
 #endif /* No IEEE 1284 support */
 
@@ -2005,17 +2083,17 @@ static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;}
 static int programmable_irq_support(struct parport *pb)
 {
        int irq, intrLine;
-       unsigned char oecr = inb (ECONTROL (pb));
+       unsigned char oecr = inb(ECONTROL(pb));
        static const int lookup[8] = {
                PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5
        };
 
-       ECR_WRITE (pb, ECR_CNF << 5); /* Configuration MODE */
+       ECR_WRITE(pb, ECR_CNF << 5); /* Configuration MODE */
 
-       intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07;
+       intrLine = (inb(CONFIGB(pb)) >> 3) & 0x07;
        irq = lookup[intrLine];
 
-       ECR_WRITE (pb, oecr);
+       ECR_WRITE(pb, oecr);
        return irq;
 }
 
@@ -2025,17 +2103,17 @@ static int irq_probe_ECP(struct parport *pb)
        unsigned long irqs;
 
        irqs = probe_irq_on();
-               
-       ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */
-       ECR_WRITE (pb, (ECR_TST << 5) | 0x04);
-       ECR_WRITE (pb, ECR_TST << 5);
+
+       ECR_WRITE(pb, ECR_SPP << 5); /* Reset FIFO */
+       ECR_WRITE(pb, (ECR_TST << 5) | 0x04);
+       ECR_WRITE(pb, ECR_TST << 5);
 
        /* If Full FIFO sure that writeIntrThreshold is generated */
-       for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++) 
-               outb (0xaa, FIFO (pb));
-               
+       for (i = 0; i < 1024 && !(inb(ECONTROL(pb)) & 0x02) ; i++)
+               outb(0xaa, FIFO(pb));
+
        pb->irq = probe_irq_off(irqs);
-       ECR_WRITE (pb, ECR_SPP << 5);
+       ECR_WRITE(pb, ECR_SPP << 5);
 
        if (pb->irq <= 0)
                pb->irq = PARPORT_IRQ_NONE;
@@ -2045,7 +2123,7 @@ static int irq_probe_ECP(struct parport *pb)
 
 /*
  * This detection seems that only works in National Semiconductors
- * This doesn't work in SMC, LGS, and Winbond 
+ * This doesn't work in SMC, LGS, and Winbond
  */
 static int irq_probe_EPP(struct parport *pb)
 {
@@ -2056,16 +2134,16 @@ static int irq_probe_EPP(struct parport *pb)
        unsigned char oecr;
 
        if (pb->modes & PARPORT_MODE_PCECR)
-               oecr = inb (ECONTROL (pb));
+               oecr = inb(ECONTROL(pb));
 
        irqs = probe_irq_on();
 
        if (pb->modes & PARPORT_MODE_PCECR)
-               frob_econtrol (pb, 0x10, 0x10);
-       
+               frob_econtrol(pb, 0x10, 0x10);
+
        clear_epp_timeout(pb);
-       parport_pc_frob_control (pb, 0x20, 0x20);
-       parport_pc_frob_control (pb, 0x10, 0x10);
+       parport_pc_frob_control(pb, 0x20, 0x20);
+       parport_pc_frob_control(pb, 0x10, 0x10);
        clear_epp_timeout(pb);
 
        /* Device isn't expecting an EPP read
@@ -2074,9 +2152,9 @@ static int irq_probe_EPP(struct parport *pb)
        parport_pc_read_epp(pb);
        udelay(20);
 
-       pb->irq = probe_irq_off (irqs);
+       pb->irq = probe_irq_off(irqs);
        if (pb->modes & PARPORT_MODE_PCECR)
-               ECR_WRITE (pb, oecr);
+               ECR_WRITE(pb, oecr);
        parport_pc_write_control(pb, 0xc);
 
        if (pb->irq <= 0)
@@ -2133,28 +2211,28 @@ static int parport_irq_probe(struct parport *pb)
 /* --- DMA detection -------------------------------------- */
 
 /* Only if chipset conforms to ECP ISA Interface Standard */
-static int programmable_dma_support (struct parport *p)
+static int programmable_dma_support(struct parport *p)
 {
-       unsigned char oecr = inb (ECONTROL (p));
+       unsigned char oecr = inb(ECONTROL(p));
        int dma;
 
-       frob_set_mode (p, ECR_CNF);
-       
-       dma = inb (CONFIGB(p)) & 0x07;
+       frob_set_mode(p, ECR_CNF);
+
+       dma = inb(CONFIGB(p)) & 0x07;
        /* 000: Indicates jumpered 8-bit DMA if read-only.
           100: Indicates jumpered 16-bit DMA if read-only. */
        if ((dma & 0x03) == 0)
                dma = PARPORT_DMA_NONE;
 
-       ECR_WRITE (p, oecr);
+       ECR_WRITE(p, oecr);
        return dma;
 }
 
-static int parport_dma_probe (struct parport *p)
+static int parport_dma_probe(struct parport *p)
 {
        const struct parport_pc_private *priv = p->private_data;
-       if (priv->ecr)
-               p->dma = programmable_dma_support(p); /* ask ECP chipset first */
+       if (priv->ecr)          /* ask ECP chipset first */
+               p->dma = programmable_dma_support(p);
        if (p->dma == PARPORT_DMA_NONE) {
                /* ask known Super-IO chips proper, although these
                   claim ECP compatible, some don't report their DMA
@@ -2212,7 +2290,7 @@ struct parport *parport_pc_probe_port(unsigned long int base,
        if (!base_res)
                goto out4;
 
-       memcpy(ops, &parport_pc_ops, sizeof (struct parport_operations));
+       memcpy(ops, &parport_pc_ops, sizeof(struct parport_operations));
        priv->ctr = 0xc;
        priv->ctr_writable = ~0x10;
        priv->ecr = 0;
@@ -2239,7 +2317,7 @@ struct parport *parport_pc_probe_port(unsigned long int base,
                        if (!parport_EPP_supported(p))
                                parport_ECPEPP_supported(p);
        }
-       if (!parport_SPP_supported (p))
+       if (!parport_SPP_supported(p))
                /* No port. */
                goto out5;
        if (priv->ecr)
@@ -2247,7 +2325,7 @@ struct parport *parport_pc_probe_port(unsigned long int base,
        else
                parport_PS2_supported(p);
 
-       p->size = (p->modes & PARPORT_MODE_EPP)?8:3;
+       p->size = (p->modes & PARPORT_MODE_EPP) ? 8 : 3;
 
        printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
        if (p->base_hi && priv->ecr)
@@ -2271,7 +2349,7 @@ struct parport *parport_pc_probe_port(unsigned long int base,
                }
        }
        if (p->dma == PARPORT_DMA_AUTO) /* To use DMA, giving the irq
-                                           is mandatory (see above) */
+                                          is mandatory (see above) */
                p->dma = PARPORT_DMA_NONE;
 
 #ifdef CONFIG_PARPORT_PC_FIFO
@@ -2288,16 +2366,23 @@ struct parport *parport_pc_probe_port(unsigned long int base,
                if (p->dma != PARPORT_DMA_NONE) {
                        printk(", dma %d", p->dma);
                        p->modes |= PARPORT_MODE_DMA;
-               }
-               else printk(", using FIFO");
-       }
-       else
+               } else
+                       printk(", using FIFO");
+       } else
                /* We can't use the DMA channel after all. */
                p->dma = PARPORT_DMA_NONE;
 #endif /* Allowed to use FIFO/DMA */
 
        printk(" [");
-#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}}
+
+#define printmode(x) \
+       {\
+               if (p->modes & PARPORT_MODE_##x) {\
+                       printk("%s%s", f ? "," : "", #x);\
+                       f++;\
+               } \
+       }
+
        {
                int f = 0;
                printmode(PCSPP);
@@ -2309,10 +2394,10 @@ struct parport *parport_pc_probe_port(unsigned long int base,
        }
 #undef printmode
 #ifndef CONFIG_PARPORT_1284
-       printk ("(,...)");
+       printk("(,...)");
 #endif /* CONFIG_PARPORT_1284 */
        printk("]\n");
-       if (probedirq != PARPORT_IRQ_NONE) 
+       if (probedirq != PARPORT_IRQ_NONE)
                printk(KERN_INFO "%s: irq %d detected\n", p->name, probedirq);
 
        /* If No ECP release the ports grabbed above. */
@@ -2328,7 +2413,7 @@ struct parport *parport_pc_probe_port(unsigned long int base,
        if (p->irq != PARPORT_IRQ_NONE) {
                if (request_irq(p->irq, parport_irq_handler,
                                 irqflags, p->name, p)) {
-                       printk (KERN_WARNING "%s: irq %d in use, "
+                       printk(KERN_WARNING "%s: irq %d in use, "
                                "resorting to polled operation\n",
                                p->name, p->irq);
                        p->irq = PARPORT_IRQ_NONE;
@@ -2338,8 +2423,8 @@ struct parport *parport_pc_probe_port(unsigned long int base,
 #ifdef CONFIG_PARPORT_PC_FIFO
 #ifdef HAS_DMA
                if (p->dma != PARPORT_DMA_NONE) {
-                       if (request_dma (p->dma, p->name)) {
-                               printk (KERN_WARNING "%s: dma %d in use, "
+                       if (request_dma(p->dma, p->name)) {
+                               printk(KERN_WARNING "%s: dma %d in use, "
                                        "resorting to PIO operation\n",
                                        p->name, p->dma);
                                p->dma = PARPORT_DMA_NONE;
@@ -2349,8 +2434,8 @@ struct parport *parport_pc_probe_port(unsigned long int base,
                                                       PAGE_SIZE,
                                                       &priv->dma_handle,
                                                       GFP_KERNEL);
-                               if (! priv->dma_buf) {
-                                       printk (KERN_WARNING "%s: "
+                               if (!priv->dma_buf) {
+                                       printk(KERN_WARNING "%s: "
                                                "cannot get buffer for DMA, "
                                                "resorting to PIO operation\n",
                                                p->name);
@@ -2369,10 +2454,10 @@ struct parport *parport_pc_probe_port(unsigned long int base,
                 * Put the ECP detected port in PS2 mode.
                 * Do this also for ports that have ECR but don't do ECP.
                 */
-               ECR_WRITE (p, 0x34);
+               ECR_WRITE(p, 0x34);
 
        parport_pc_write_data(p, 0);
-       parport_pc_data_forward (p);
+       parport_pc_data_forward(p);
 
        /* Now that we've told the sharing engine about the port, and
           found out its characteristics, let the high-level drivers
@@ -2380,7 +2465,7 @@ struct parport *parport_pc_probe_port(unsigned long int base,
        spin_lock(&ports_lock);
        list_add(&priv->list, &ports_list);
        spin_unlock(&ports_lock);
-       parport_announce_port (p);
+       parport_announce_port(p);
 
        return p;
 
@@ -2393,18 +2478,17 @@ out5:
 out4:
        parport_put_port(p);
 out3:
-       kfree (priv);
+       kfree(priv);
 out2:
-       kfree (ops);
+       kfree(ops);
 out1:
        if (pdev)
                platform_device_unregister(pdev);
        return NULL;
 }
+EXPORT_SYMBOL(parport_pc_probe_port);
 
-EXPORT_SYMBOL (parport_pc_probe_port);
-
-void parport_pc_unregister_port (struct parport *p)
+void parport_pc_unregister_port(struct parport *p)
 {
        struct parport_pc_private *priv = p->private_data;
        struct parport_operations *ops = p->ops;
@@ -2430,17 +2514,16 @@ void parport_pc_unregister_port (struct parport *p)
                                    priv->dma_buf,
                                    priv->dma_handle);
 #endif
-       kfree (p->private_data);
+       kfree(p->private_data);
        parport_put_port(p);
-       kfree (ops); /* hope no-one cached it */
+       kfree(ops); /* hope no-one cached it */
 }
-
-EXPORT_SYMBOL (parport_pc_unregister_port);
+EXPORT_SYMBOL(parport_pc_unregister_port);
 
 #ifdef CONFIG_PCI
 
 /* ITE support maintained by Rich Liu <richliu@poorman.org> */
-static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq,
+static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq,
                                         int autodma,
                                         const struct parport_pc_via_data *via)
 {
@@ -2452,73 +2535,74 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq,
        int irq;
        int i;
 
-       DPRINTK (KERN_DEBUG "sio_ite_8872_probe()\n");
-       
-       // make sure which one chip
-       for(i = 0; i < 5; i++) {
+       DPRINTK(KERN_DEBUG "sio_ite_8872_probe()\n");
+
+       /* make sure which one chip */
+       for (i = 0; i < 5; i++) {
                base_res = request_region(inta_addr[i], 32, "it887x");
                if (base_res) {
                        int test;
-                       pci_write_config_dword (pdev, 0x60,
+                       pci_write_config_dword(pdev, 0x60,
                                                0xe5000000 | inta_addr[i]);
-                       pci_write_config_dword (pdev, 0x78,
+                       pci_write_config_dword(pdev, 0x78,
                                                0x00000000 | inta_addr[i]);
-                       test = inb (inta_addr[i]);
-                       if (test != 0xff) break;
+                       test = inb(inta_addr[i]);
+                       if (test != 0xff)
+                               break;
                        release_region(inta_addr[i], 0x8);
                }
        }
-       if(i >= 5) {
-               printk (KERN_INFO "parport_pc: cannot find ITE8872 INTA\n");
+       if (i >= 5) {
+               printk(KERN_INFO "parport_pc: cannot find ITE8872 INTA\n");
                return 0;
        }
 
-       type = inb (inta_addr[i] + 0x18);
+       type = inb(inta_addr[i] + 0x18);
        type &= 0x0f;
 
        switch (type) {
        case 0x2:
-               printk (KERN_INFO "parport_pc: ITE8871 found (1P)\n");
+               printk(KERN_INFO "parport_pc: ITE8871 found (1P)\n");
                ite8872set = 0x64200000;
                break;
        case 0xa:
-               printk (KERN_INFO "parport_pc: ITE8875 found (1P)\n");
+               printk(KERN_INFO "parport_pc: ITE8875 found (1P)\n");
                ite8872set = 0x64200000;
                break;
        case 0xe:
-               printk (KERN_INFO "parport_pc: ITE8872 found (2S1P)\n");
+               printk(KERN_INFO "parport_pc: ITE8872 found (2S1P)\n");
                ite8872set = 0x64e00000;
                break;
        case 0x6:
-               printk (KERN_INFO "parport_pc: ITE8873 found (1S)\n");
+               printk(KERN_INFO "parport_pc: ITE8873 found (1S)\n");
                return 0;
        case 0x8:
-               DPRINTK (KERN_DEBUG "parport_pc: ITE8874 found (2S)\n");
+               DPRINTK(KERN_DEBUG "parport_pc: ITE8874 found (2S)\n");
                return 0;
        default:
-               printk (KERN_INFO "parport_pc: unknown ITE887x\n");
-               printk (KERN_INFO "parport_pc: please mail 'lspci -nvv' "
+               printk(KERN_INFO "parport_pc: unknown ITE887x\n");
+               printk(KERN_INFO "parport_pc: please mail 'lspci -nvv' "
                        "output to Rich.Liu@ite.com.tw\n");
                return 0;
        }
 
-       pci_read_config_byte (pdev, 0x3c, &ite8872_irq);
-       pci_read_config_dword (pdev, 0x1c, &ite8872_lpt);
+       pci_read_config_byte(pdev, 0x3c, &ite8872_irq);
+       pci_read_config_dword(pdev, 0x1c, &ite8872_lpt);
        ite8872_lpt &= 0x0000ff00;
-       pci_read_config_dword (pdev, 0x20, &ite8872_lpthi);
+       pci_read_config_dword(pdev, 0x20, &ite8872_lpthi);
        ite8872_lpthi &= 0x0000ff00;
-       pci_write_config_dword (pdev, 0x6c, 0xe3000000 | ite8872_lpt);
-       pci_write_config_dword (pdev, 0x70, 0xe3000000 | ite8872_lpthi);
-       pci_write_config_dword (pdev, 0x80, (ite8872_lpthi<<16) | ite8872_lpt);
-       // SET SPP&EPP , Parallel Port NO DMA , Enable All Function
-       // SET Parallel IRQ
-       pci_write_config_dword (pdev, 0x9c,
+       pci_write_config_dword(pdev, 0x6c, 0xe3000000 | ite8872_lpt);
+       pci_write_config_dword(pdev, 0x70, 0xe3000000 | ite8872_lpthi);
+       pci_write_config_dword(pdev, 0x80, (ite8872_lpthi<<16) | ite8872_lpt);
+       /* SET SPP&EPP , Parallel Port NO DMA , Enable All Function */
+       /* SET Parallel IRQ */
+       pci_write_config_dword(pdev, 0x9c,
                                ite8872set | (ite8872_irq * 0x11111));
 
-       DPRINTK (KERN_DEBUG "ITE887x: The IRQ is %d.\n", ite8872_irq);
-       DPRINTK (KERN_DEBUG "ITE887x: The PARALLEL I/O port is 0x%x.\n",
+       DPRINTK(KERN_DEBUG "ITE887x: The IRQ is %d.\n", ite8872_irq);
+       DPRINTK(KERN_DEBUG "ITE887x: The PARALLEL I/O port is 0x%x.\n",
                 ite8872_lpt);
-       DPRINTK (KERN_DEBUG "ITE887x: The PARALLEL I/O porthi is 0x%x.\n",
+       DPRINTK(KERN_DEBUG "ITE887x: The PARALLEL I/O porthi is 0x%x.\n",
                 ite8872_lpthi);
 
        /* Let the user (or defaults) steer us away from interrupts */
@@ -2530,14 +2614,14 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq,
         * Release the resource so that parport_pc_probe_port can get it.
         */
        release_resource(base_res);
-       if (parport_pc_probe_port (ite8872_lpt, ite8872_lpthi,
+       if (parport_pc_probe_port(ite8872_lpt, ite8872_lpthi,
                                   irq, PARPORT_DMA_NONE, &pdev->dev, 0)) {
-               printk (KERN_INFO
+               printk(KERN_INFO
                        "parport_pc: ITE 8872 parallel port: io=0x%X",
-                       ite8872_lpt);
+                                                               ite8872_lpt);
                if (irq != PARPORT_IRQ_NONE)
-                       printk (", irq=%d", irq);
-               printk ("\n");
+                       printk(", irq=%d", irq);
+               printk("\n");
                return 1;
        }
 
@@ -2546,7 +2630,7 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq,
 
 /* VIA 8231 support by Pavel Fedin <sonic_amiga@rambler.ru>
    based on VIA 686a support code by Jeff Garzik <jgarzik@pobox.com> */
-static int __devinitdata parport_init_mode = 0;
+static int __devinitdata parport_init_mode;
 
 /* Data for two known VIA chips */
 static struct parport_pc_via_data via_686a_data __devinitdata = {
@@ -2568,7 +2652,7 @@ static struct parport_pc_via_data via_8231_data __devinitdata = {
        0xF6
 };
 
-static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq,
+static int __devinit sio_via_probe(struct pci_dev *pdev, int autoirq,
                                    int autodma,
                                    const struct parport_pc_via_data *via)
 {
@@ -2580,38 +2664,38 @@ static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq,
 
        printk(KERN_DEBUG "parport_pc: VIA 686A/8231 detected\n");
 
-       switch(parport_init_mode)
-       {
+       switch (parport_init_mode) {
        case 1:
-           printk(KERN_DEBUG "parport_pc: setting SPP mode\n");
-           siofunc = VIA_FUNCTION_PARPORT_SPP;
-           break;
+               printk(KERN_DEBUG "parport_pc: setting SPP mode\n");
+               siofunc = VIA_FUNCTION_PARPORT_SPP;
+               break;
        case 2:
-           printk(KERN_DEBUG "parport_pc: setting PS/2 mode\n");
-           siofunc = VIA_FUNCTION_PARPORT_SPP;
-           ppcontrol = VIA_PARPORT_BIDIR;
-           break;
+               printk(KERN_DEBUG "parport_pc: setting PS/2 mode\n");
+               siofunc = VIA_FUNCTION_PARPORT_SPP;
+               ppcontrol = VIA_PARPORT_BIDIR;
+               break;
        case 3:
-           printk(KERN_DEBUG "parport_pc: setting EPP mode\n");
-           siofunc = VIA_FUNCTION_PARPORT_EPP;
-           ppcontrol = VIA_PARPORT_BIDIR;
-           have_epp = 1;
-           break;
+               printk(KERN_DEBUG "parport_pc: setting EPP mode\n");
+               siofunc = VIA_FUNCTION_PARPORT_EPP;
+               ppcontrol = VIA_PARPORT_BIDIR;
+               have_epp = 1;
+               break;
        case 4:
-           printk(KERN_DEBUG "parport_pc: setting ECP mode\n");
-           siofunc = VIA_FUNCTION_PARPORT_ECP;
-           ppcontrol = VIA_PARPORT_BIDIR;
-           break;
+               printk(KERN_DEBUG "parport_pc: setting ECP mode\n");
+               siofunc = VIA_FUNCTION_PARPORT_ECP;
+               ppcontrol = VIA_PARPORT_BIDIR;
+               break;
        case 5:
-           printk(KERN_DEBUG "parport_pc: setting EPP+ECP mode\n");
-           siofunc = VIA_FUNCTION_PARPORT_ECP;
-           ppcontrol = VIA_PARPORT_BIDIR|VIA_PARPORT_ECPEPP;
-           have_epp = 1;
-           break;
-        default:
-           printk(KERN_DEBUG "parport_pc: probing current configuration\n");
-           siofunc = VIA_FUNCTION_PROBE;
-           break;
+               printk(KERN_DEBUG "parport_pc: setting EPP+ECP mode\n");
+               siofunc = VIA_FUNCTION_PARPORT_ECP;
+               ppcontrol = VIA_PARPORT_BIDIR|VIA_PARPORT_ECPEPP;
+               have_epp = 1;
+               break;
+       default:
+               printk(KERN_DEBUG
+                       "parport_pc: probing current configuration\n");
+               siofunc = VIA_FUNCTION_PROBE;
+               break;
        }
        /*
         * unlock super i/o configuration
@@ -2622,38 +2706,36 @@ static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq,
 
        /* Bits 1-0: Parallel Port Mode / Enable */
        outb(via->viacfg_function, VIA_CONFIG_INDEX);
-       tmp = inb (VIA_CONFIG_DATA);
+       tmp = inb(VIA_CONFIG_DATA);
        /* Bit 5: EPP+ECP enable; bit 7: PS/2 bidirectional port enable */
        outb(via->viacfg_parport_control, VIA_CONFIG_INDEX);
-       tmp2 = inb (VIA_CONFIG_DATA);
-       if (siofunc == VIA_FUNCTION_PROBE)
-       {
-           siofunc = tmp & VIA_FUNCTION_PARPORT_DISABLE;
-           ppcontrol = tmp2;
+       tmp2 = inb(VIA_CONFIG_DATA);
+       if (siofunc == VIA_FUNCTION_PROBE) {
+               siofunc = tmp & VIA_FUNCTION_PARPORT_DISABLE;
+               ppcontrol = tmp2;
+       } else {
+               tmp &= ~VIA_FUNCTION_PARPORT_DISABLE;
+               tmp |= siofunc;
+               outb(via->viacfg_function, VIA_CONFIG_INDEX);
+               outb(tmp, VIA_CONFIG_DATA);
+               tmp2 &= ~(VIA_PARPORT_BIDIR|VIA_PARPORT_ECPEPP);
+               tmp2 |= ppcontrol;
+               outb(via->viacfg_parport_control, VIA_CONFIG_INDEX);
+               outb(tmp2, VIA_CONFIG_DATA);
        }
-       else
-       {
-           tmp &= ~VIA_FUNCTION_PARPORT_DISABLE;
-           tmp |= siofunc;
-           outb(via->viacfg_function, VIA_CONFIG_INDEX);
-           outb(tmp, VIA_CONFIG_DATA);
-           tmp2 &= ~(VIA_PARPORT_BIDIR|VIA_PARPORT_ECPEPP);
-           tmp2 |= ppcontrol;
-           outb(via->viacfg_parport_control, VIA_CONFIG_INDEX);
-           outb(tmp2, VIA_CONFIG_DATA);
-       }
-       
+
        /* Parallel Port I/O Base Address, bits 9-2 */
        outb(via->viacfg_parport_base, VIA_CONFIG_INDEX);
        port1 = inb(VIA_CONFIG_DATA) << 2;
-       
-       printk (KERN_DEBUG "parport_pc: Current parallel port base: 0x%X\n",port1);
-       if ((port1 == 0x3BC) && have_epp)
-       {
-           outb(via->viacfg_parport_base, VIA_CONFIG_INDEX);
-           outb((0x378 >> 2), VIA_CONFIG_DATA);
-           printk(KERN_DEBUG "parport_pc: Parallel port base changed to 0x378\n");
-           port1 = 0x378;
+
+       printk(KERN_DEBUG "parport_pc: Current parallel port base: 0x%X\n",
+                                                                       port1);
+       if (port1 == 0x3BC && have_epp) {
+               outb(via->viacfg_parport_base, VIA_CONFIG_INDEX);
+               outb((0x378 >> 2), VIA_CONFIG_DATA);
+               printk(KERN_DEBUG
+                       "parport_pc: Parallel port base changed to 0x378\n");
+               port1 = 0x378;
        }
 
        /*
@@ -2667,36 +2749,39 @@ static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq,
                printk(KERN_INFO "parport_pc: VIA parallel port disabled in BIOS\n");
                return 0;
        }
-       
+
        /* Bits 7-4: PnP Routing for Parallel Port IRQ */
        pci_read_config_byte(pdev, via->via_pci_parport_irq_reg, &tmp);
        irq = ((tmp & VIA_IRQCONTROL_PARALLEL) >> 4);
 
-       if (siofunc == VIA_FUNCTION_PARPORT_ECP)
-       {
-           /* Bits 3-2: PnP Routing for Parallel Port DMA */
-           pci_read_config_byte(pdev, via->via_pci_parport_dma_reg, &tmp);
-           dma = ((tmp & VIA_DMACONTROL_PARALLEL) >> 2);
-       }
-       else
-           /* if ECP not enabled, DMA is not enabled, assumed bogus 'dma' value */
-           dma = PARPORT_DMA_NONE;
+       if (siofunc == VIA_FUNCTION_PARPORT_ECP) {
+               /* Bits 3-2: PnP Routing for Parallel Port DMA */
+               pci_read_config_byte(pdev, via->via_pci_parport_dma_reg, &tmp);
+               dma = ((tmp & VIA_DMACONTROL_PARALLEL) >> 2);
+       } else
+               /* if ECP not enabled, DMA is not enabled, assumed
+                  bogus 'dma' value */
+               dma = PARPORT_DMA_NONE;
 
        /* Let the user (or defaults) steer us away from interrupts and DMA */
        if (autoirq == PARPORT_IRQ_NONE) {
-           irq = PARPORT_IRQ_NONE;
-           dma = PARPORT_DMA_NONE;
+               irq = PARPORT_IRQ_NONE;
+               dma = PARPORT_DMA_NONE;
        }
        if (autodma == PARPORT_DMA_NONE)
-           dma = PARPORT_DMA_NONE;
+               dma = PARPORT_DMA_NONE;
 
        switch (port1) {
-       case 0x3bc: port2 = 0x7bc; break;
-       case 0x378: port2 = 0x778; break;
-       case 0x278: port2 = 0x678; break;
+       case 0x3bc:
+               port2 = 0x7bc; break;
+       case 0x378:
+               port2 = 0x778; break;
+       case 0x278:
+               port2 = 0x678; break;
        default:
-               printk(KERN_INFO "parport_pc: Weird VIA parport base 0x%X, ignoring\n",
-                       port1);
+               printk(KERN_INFO
+                       "parport_pc: Weird VIA parport base 0x%X, ignoring\n",
+                                                                       port1);
                return 0;
        }
 
@@ -2714,17 +2799,17 @@ static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq,
        }
 
        /* finally, do the probe with values obtained */
-       if (parport_pc_probe_port (port1, port2, irq, dma, &pdev->dev, 0)) {
-               printk (KERN_INFO
+       if (parport_pc_probe_port(port1, port2, irq, dma, &pdev->dev, 0)) {
+               printk(KERN_INFO
                        "parport_pc: VIA parallel port: io=0x%X", port1);
                if (irq != PARPORT_IRQ_NONE)
-                       printk (", irq=%d", irq);
+                       printk(", irq=%d", irq);
                if (dma != PARPORT_DMA_NONE)
-                       printk (", dma=%d", dma);
-               printk ("\n");
+                       printk(", dma=%d", dma);
+               printk("\n");
                return 1;
        }
-       
+
        printk(KERN_WARNING "parport_pc: Strange, can't probe VIA parallel port: io=0x%X, irq=%d, dma=%d\n",
                port1, irq, dma);
        return 0;
@@ -2732,8 +2817,8 @@ static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq,
 
 
 enum parport_pc_sio_types {
-       sio_via_686a = 0,       /* Via VT82C686A motherboard Super I/O */
-       sio_via_8231,           /* Via VT8231 south bridge integrated Super IO */
+       sio_via_686a = 0,   /* Via VT82C686A motherboard Super I/O */
+       sio_via_8231,       /* Via VT8231 south bridge integrated Super IO */
        sio_ite_8872,
        last_sio
 };
@@ -2804,15 +2889,15 @@ enum parport_pc_pci_cards {
 };
 
 
-/* each element directly indexed from enum list, above 
+/* each element directly indexed from enum list, above
  * (but offset by last_sio) */
 static struct parport_pc_pci {
        int numports;
        struct { /* BAR (base address registers) numbers in the config
-                    space header */
+                   space header */
                int lo;
-               int hi; /* -1 if not there, >6 for offset-method (max
-                           BAR is 6) */
+               int hi;
+               /* -1 if not there, >6 for offset-method (max BAR is 6) */
        } addr[4];
 
        /* If set, this is called immediately after pci_enable_device.
@@ -2857,7 +2942,7 @@ static struct parport_pc_pci {
        /* timedia_4018  */             { 2, { { 0, 1 }, { 2, 3 }, } },
        /* timedia_9018a */             { 2, { { 0, 1 }, { 2, 3 }, } },
                                        /* SYBA uses fixed offsets in
-                                           a 1K io window */
+                                          a 1K io window */
        /* syba_2p_epp AP138B */        { 2, { { 0, 0x078 }, { 0, 0x178 }, } },
        /* syba_1p_ecp W83787 */        { 1, { { 0, 0x078 }, } },
        /* titan_010l */                { 1, { { 3, -1 }, } },
@@ -2873,11 +2958,14 @@ static struct parport_pc_pci {
        /* oxsemi_pcie_pport */         { 1, { { 0, 1 }, } },
        /* aks_0100 */                  { 1, { { 0, -1 }, } },
        /* mobility_pp */               { 1, { { 0, 1 }, } },
-       /* netmos_9705 */               { 1, { { 0, -1 }, } }, /* untested */
-        /* netmos_9715 */               { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */
-        /* netmos_9755 */               { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */
-       /* netmos_9805 */               { 1, { { 0, -1 }, } }, /* untested */
-       /* netmos_9815 */               { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */
+
+       /* The netmos entries below are untested */
+       /* netmos_9705 */               { 1, { { 0, -1 }, } },
+       /* netmos_9715 */               { 2, { { 0, 1 }, { 2, 3 },} },
+       /* netmos_9755 */               { 2, { { 0, 1 }, { 2, 3 },} },
+       /* netmos_9805 */               { 1, { { 0, -1 }, } },
+       /* netmos_9815 */               { 2, { { 0, -1 }, { 2, -1 }, } },
+
        /* quatech_sppxp100 */          { 1, { { 0, 1 }, } },
 };
 
@@ -2906,7 +2994,7 @@ static const struct pci_device_id parport_pc_pci_tbl[] = {
        { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_BOCA_IOPPAR,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, boca_ioppar },
        { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-         PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 0,0, plx_9050 },
+         PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 0, 0, plx_9050 },
        /* PCI_VENDOR_ID_TIMEDIA/SUNIX has many differing cards ...*/
        { 0x1409, 0x7168, 0x1409, 0x4078, 0, 0, timedia_4078a },
        { 0x1409, 0x7168, 0x1409, 0x4079, 0, 0, timedia_4079h },
@@ -2940,7 +3028,8 @@ static const struct pci_device_id parport_pc_pci_tbl[] = {
        { 0x9710, 0x9805, 0x1000, 0x0010, 0, 0, titan_1284p1 },
        { 0x9710, 0x9815, 0x1000, 0x0020, 0, 0, titan_1284p2 },
        /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
-       { 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p}, /* AFAVLAB_TK9902 */
+       /* AFAVLAB_TK9902 */
+       { 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p},
        { 0x14db, 0x2121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2p},
        { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952PP,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_952 },
@@ -2983,14 +3072,14 @@ static const struct pci_device_id parport_pc_pci_tbl[] = {
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 },
        { 0, } /* terminate list */
 };
-MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
+MODULE_DEVICE_TABLE(pci, parport_pc_pci_tbl);
 
 struct pci_parport_data {
        int num;
        struct parport *ports[2];
 };
 
-static int parport_pc_pci_probe (struct pci_dev *dev,
+static int parport_pc_pci_probe(struct pci_dev *dev,
                                           const struct pci_device_id *id)
 {
        int err, count, n, i = id->driver_data;
@@ -3003,7 +3092,8 @@ static int parport_pc_pci_probe (struct pci_dev *dev,
        /* This is a PCI card */
        i -= last_sio;
        count = 0;
-       if ((err = pci_enable_device (dev)) != 0)
+       err = pci_enable_device(dev);
+       if (err)
                return err;
 
        data = kmalloc(sizeof(struct pci_parport_data), GFP_KERNEL);
@@ -3011,7 +3101,7 @@ static int parport_pc_pci_probe (struct pci_dev *dev,
                return -ENOMEM;
 
        if (cards[i].preinit_hook &&
-           cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) {
+           cards[i].preinit_hook(dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) {
                kfree(data);
                return -ENODEV;
        }
@@ -3021,25 +3111,25 @@ static int parport_pc_pci_probe (struct pci_dev *dev,
                int hi = cards[i].addr[n].hi;
                int irq;
                unsigned long io_lo, io_hi;
-               io_lo = pci_resource_start (dev, lo);
+               io_lo = pci_resource_start(dev, lo);
                io_hi = 0;
                if ((hi >= 0) && (hi <= 6))
-                       io_hi = pci_resource_start (dev, hi);
+                       io_hi = pci_resource_start(dev, hi);
                else if (hi > 6)
                        io_lo += hi; /* Reinterpret the meaning of
-                                        "hi" as an offset (see SYBA
-                                        def.) */
+                                       "hi" as an offset (see SYBA
+                                       def.) */
                /* TODO: test if sharing interrupts works */
                irq = dev->irq;
                if (irq == IRQ_NONE) {
-                       printk (KERN_DEBUG
+                       printk(KERN_DEBUG
        "PCI parallel port detected: %04x:%04x, I/O at %#lx(%#lx)\n",
                                parport_pc_pci_tbl[i + last_sio].vendor,
                                parport_pc_pci_tbl[i + last_sio].device,
                                io_lo, io_hi);
                        irq = PARPORT_IRQ_NONE;
                } else {
-                       printk (KERN_DEBUG
+                       printk(KERN_DEBUG
        "PCI parallel port detected: %04x:%04x, I/O at %#lx(%#lx), IRQ %d\n",
                                parport_pc_pci_tbl[i + last_sio].vendor,
                                parport_pc_pci_tbl[i + last_sio].device,
@@ -3056,7 +3146,7 @@ static int parport_pc_pci_probe (struct pci_dev *dev,
        data->num = count;
 
        if (cards[i].postinit_hook)
-               cards[i].postinit_hook (dev, count == 0);
+               cards[i].postinit_hook(dev, count == 0);
 
        if (count) {
                pci_set_drvdata(dev, data);
@@ -3090,7 +3180,7 @@ static struct pci_driver parport_pc_pci_driver = {
        .remove         = __devexit_p(parport_pc_pci_remove),
 };
 
-static int __init parport_pc_init_superio (int autoirq, int autodma)
+static int __init parport_pc_init_superio(int autoirq, int autodma)
 {
        const struct pci_device_id *id;
        struct pci_dev *pdev = NULL;
@@ -3101,8 +3191,9 @@ static int __init parport_pc_init_superio (int autoirq, int autodma)
                if (id == NULL || id->driver_data >= last_sio)
                        continue;
 
-               if (parport_pc_superio_info[id->driver_data].probe
-                       (pdev, autoirq, autodma,parport_pc_superio_info[id->driver_data].via)) {
+               if (parport_pc_superio_info[id->driver_data].probe(
+                       pdev, autoirq, autodma,
+                       parport_pc_superio_info[id->driver_data].via)) {
                        ret++;
                }
        }
@@ -3111,7 +3202,10 @@ static int __init parport_pc_init_superio (int autoirq, int autodma)
 }
 #else
 static struct pci_driver parport_pc_pci_driver;
-static int __init parport_pc_init_superio(int autoirq, int autodma) {return 0;}
+static int __init parport_pc_init_superio(int autoirq, int autodma)
+{
+       return 0;
+}
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_PNP
@@ -3124,44 +3218,45 @@ static const struct pnp_device_id parport_pc_pnp_tbl[] = {
        { }
 };
 
-MODULE_DEVICE_TABLE(pnp,parport_pc_pnp_tbl);
+MODULE_DEVICE_TABLE(pnp, parport_pc_pnp_tbl);
 
-static int parport_pc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id)
+static int parport_pc_pnp_probe(struct pnp_dev *dev,
+                                               const struct pnp_device_id *id)
 {
        struct parport *pdata;
        unsigned long io_lo, io_hi;
        int dma, irq;
 
-       if (pnp_port_valid(dev,0) &&
-               !(pnp_port_flags(dev,0) & IORESOURCE_DISABLED)) {
-               io_lo = pnp_port_start(dev,0);
+       if (pnp_port_valid(dev, 0) &&
+               !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) {
+               io_lo = pnp_port_start(dev, 0);
        } else
                return -EINVAL;
 
-       if (pnp_port_valid(dev,1) &&
-               !(pnp_port_flags(dev,1) & IORESOURCE_DISABLED)) {
-               io_hi = pnp_port_start(dev,1);
+       if (pnp_port_valid(dev, 1) &&
+               !(pnp_port_flags(dev, 1) & IORESOURCE_DISABLED)) {
+               io_hi = pnp_port_start(dev, 1);
        } else
                io_hi = 0;
 
-       if (pnp_irq_valid(dev,0) &&
-               !(pnp_irq_flags(dev,0) & IORESOURCE_DISABLED)) {
-               irq = pnp_irq(dev,0);
+       if (pnp_irq_valid(dev, 0) &&
+               !(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED)) {
+               irq = pnp_irq(dev, 0);
        } else
                irq = PARPORT_IRQ_NONE;
 
-       if (pnp_dma_valid(dev,0) &&
-               !(pnp_dma_flags(dev,0) & IORESOURCE_DISABLED)) {
-               dma = pnp_dma(dev,0);
+       if (pnp_dma_valid(dev, 0) &&
+               !(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED)) {
+               dma = pnp_dma(dev, 0);
        } else
                dma = PARPORT_DMA_NONE;
 
        dev_info(&dev->dev, "reported by %s\n", dev->protocol->name);
-       if (!(pdata = parport_pc_probe_port(io_lo, io_hi,
-                                       irq, dma, &dev->dev, 0)))
+       pdata = parport_pc_probe_port(io_lo, io_hi, irq, dma, &dev->dev, 0);
+       if (pdata == NULL)
                return -ENODEV;
 
-       pnp_set_drvdata(dev,pdata);
+       pnp_set_drvdata(dev, pdata);
        return 0;
 }
 
@@ -3203,7 +3298,7 @@ static struct platform_driver parport_pc_platform_driver = {
 
 /* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */
 static int __devinit __attribute__((unused))
-parport_pc_find_isa_ports (int autoirq, int autodma)
+parport_pc_find_isa_ports(int autoirq, int autodma)
 {
        int count = 0;
 
@@ -3227,7 +3322,7 @@ parport_pc_find_isa_ports (int autoirq, int autodma)
  * autoirq is PARPORT_IRQ_NONE, PARPORT_IRQ_AUTO, or PARPORT_IRQ_PROBEONLY
  * autodma is PARPORT_DMA_NONE or PARPORT_DMA_AUTO
  */
-static void __init parport_pc_find_ports (int autoirq, int autodma)
+static void __init parport_pc_find_ports(int autoirq, int autodma)
 {
        int count = 0, err;
 
@@ -3261,11 +3356,18 @@ static void __init parport_pc_find_ports (int autoirq, int autodma)
  *     syntax and keep in mind that code below is a cleaned up version.
  */
 
-static int __initdata io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
-static int __initdata io_hi[PARPORT_PC_MAX_PORTS+1] =
-       { [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO };
-static int __initdata dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE };
-static int __initdata irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
+static int __initdata io[PARPORT_PC_MAX_PORTS+1] = {
+       [0 ... PARPORT_PC_MAX_PORTS] = 0
+};
+static int __initdata io_hi[PARPORT_PC_MAX_PORTS+1] = {
+       [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO
+};
+static int __initdata dmaval[PARPORT_PC_MAX_PORTS] = {
+       [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE
+};
+static int __initdata irqval[PARPORT_PC_MAX_PORTS] = {
+       [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY
+};
 
 static int __init parport_parse_param(const char *s, int *val,
                                int automatic, int none, int nofifo)
@@ -3306,18 +3408,19 @@ static int __init parport_parse_dma(const char *dmastr, int *val)
 #ifdef CONFIG_PCI
 static int __init parport_init_mode_setup(char *str)
 {
-       printk(KERN_DEBUG "parport_pc.c: Specified parameter parport_init_mode=%s\n", str);
-
-       if (!strcmp (str, "spp"))
-               parport_init_mode=1;
-       if (!strcmp (str, "ps2"))
-               parport_init_mode=2;
-       if (!strcmp (str, "epp"))
-               parport_init_mode=3;
-       if (!strcmp (str, "ecp"))
-               parport_init_mode=4;
-       if (!strcmp (str, "ecpepp"))
-               parport_init_mode=5;
+       printk(KERN_DEBUG
+            "parport_pc.c: Specified parameter parport_init_mode=%s\n", str);
+
+       if (!strcmp(str, "spp"))
+               parport_init_mode = 1;
+       if (!strcmp(str, "ps2"))
+               parport_init_mode = 2;
+       if (!strcmp(str, "epp"))
+               parport_init_mode = 3;
+       if (!strcmp(str, "ecp"))
+               parport_init_mode = 4;
+       if (!strcmp(str, "ecpepp"))
+               parport_init_mode = 5;
        return 1;
 }
 #endif
@@ -3341,7 +3444,8 @@ module_param(verbose_probing, int, 0644);
 #endif
 #ifdef CONFIG_PCI
 static char *init_mode;
-MODULE_PARM_DESC(init_mode, "Initialise mode for VIA VT8231 port (spp, ps2, epp, ecp or ecpepp)");
+MODULE_PARM_DESC(init_mode,
+       "Initialise mode for VIA VT8231 port (spp, ps2, epp, ecp or ecpepp)");
 module_param(init_mode, charp, 0);
 #endif
 
@@ -3372,7 +3476,7 @@ static int __init parse_parport_params(void)
                                irqval[0] = val;
                                break;
                        default:
-                               printk (KERN_WARNING
+                               printk(KERN_WARNING
                                        "parport_pc: irq specified "
                                        "without base address.  Use 'io=' "
                                        "to specify one\n");
@@ -3385,7 +3489,7 @@ static int __init parse_parport_params(void)
                                dmaval[0] = val;
                                break;
                        default:
-                               printk (KERN_WARNING
+                               printk(KERN_WARNING
                                        "parport_pc: dma specified "
                                        "without base address.  Use 'io=' "
                                        "to specify one\n");
@@ -3396,7 +3500,7 @@ static int __init parse_parport_params(void)
 
 #else
 
-static int parport_setup_ptr __initdata = 0;
+static int parport_setup_ptr __initdata;
 
 /*
  * Acceptable parameters:
@@ -3407,7 +3511,7 @@ static int parport_setup_ptr __initdata = 0;
  *
  * IRQ/DMA may be numeric or 'auto' or 'none'
  */
-static int __init parport_setup (char *str)
+static int __init parport_setup(char *str)
 {
        char *endptr;
        char *sep;
@@ -3419,15 +3523,15 @@ static int __init parport_setup (char *str)
                return 1;
        }
 
-       if (!strncmp (str, "auto", 4)) {
+       if (!strncmp(str, "auto", 4)) {
                irqval[0] = PARPORT_IRQ_AUTO;
                dmaval[0] = PARPORT_DMA_AUTO;
                return 1;
        }
 
-       val = simple_strtoul (str, &endptr, 0);
+       val = simple_strtoul(str, &endptr, 0);
        if (endptr == str) {
-               printk (KERN_WARNING "parport=%s not understood\n", str);
+               printk(KERN_WARNING "parport=%s not understood\n", str);
                return 1;
        }
 
@@ -3461,7 +3565,7 @@ static int __init parse_parport_params(void)
        return io[0] == PARPORT_DISABLE;
 }
 
-__setup ("parport=", parport_setup);
+__setup("parport=", parport_setup);
 
 /*
  * Acceptable parameters:
@@ -3469,7 +3573,7 @@ __setup ("parport=", parport_setup);
  * parport_init_mode=[spp|ps2|epp|ecp|ecpepp]
  */
 #ifdef CONFIG_PCI
-__setup("parport_init_mode=",parport_init_mode_setup);
+__setup("parport_init_mode=", parport_init_mode_setup);
 #endif
 #endif
 
@@ -3493,13 +3597,13 @@ static int __init parport_pc_init(void)
                for (i = 0; i < PARPORT_PC_MAX_PORTS; i++) {
                        if (!io[i])
                                break;
-                       if ((io_hi[i]) == PARPORT_IOHI_AUTO)
-                              io_hi[i] = 0x400 + io[i];
+                       if (io_hi[i] == PARPORT_IOHI_AUTO)
+                               io_hi[i] = 0x400 + io[i];
                        parport_pc_probe_port(io[i], io_hi[i],
-                                         irqval[i], dmaval[i], NULL, 0);
+                                       irqval[i], dmaval[i], NULL, 0);
                }
        } else
-               parport_pc_find_ports (irqval[0], dmaval[0]);
+               parport_pc_find_ports(irqval[0], dmaval[0]);
 
        return 0;
 }
@@ -3507,9 +3611,9 @@ static int __init parport_pc_init(void)
 static void __exit parport_pc_exit(void)
 {
        if (pci_registered_parport)
-               pci_unregister_driver (&parport_pc_pci_driver);
+               pci_unregister_driver(&parport_pc_pci_driver);
        if (pnp_registered_parport)
-               pnp_unregister_driver (&parport_pc_pnp_driver);
+               pnp_unregister_driver(&parport_pc_pnp_driver);
        platform_driver_unregister(&parport_pc_platform_driver);
 
        while (!list_empty(&ports_list)) {
index dd18f857dfb042d8d5802bfbbab57c617054b3f4..42e4260c3b12311e3793102b76ec136f5f94352e 100644 (file)
@@ -153,45 +153,47 @@ int ibmphp_init_devno(struct slot **cur_slot)
                return -1;
        }
        for (loop = 0; loop < len; loop++) {
-               if ((*cur_slot)->number == rtable->slots[loop].slot) {
-               if ((*cur_slot)->bus == rtable->slots[loop].bus) {
+               if ((*cur_slot)->number == rtable->slots[loop].slot &&
+                   (*cur_slot)->bus == rtable->slots[loop].bus) {
+                       struct io_apic_irq_attr irq_attr;
+
                        (*cur_slot)->device = PCI_SLOT(rtable->slots[loop].devfn);
                        for (i = 0; i < 4; i++)
                                (*cur_slot)->irq[i] = IO_APIC_get_PCI_irq_vector((int) (*cur_slot)->bus,
-                                               (int) (*cur_slot)->device, i);
-
-                               debug("(*cur_slot)->irq[0] = %x\n",
-                                               (*cur_slot)->irq[0]);
-                               debug("(*cur_slot)->irq[1] = %x\n",
-                                               (*cur_slot)->irq[1]);
-                               debug("(*cur_slot)->irq[2] = %x\n",
-                                               (*cur_slot)->irq[2]);
-                               debug("(*cur_slot)->irq[3] = %x\n",
-                                               (*cur_slot)->irq[3]);
-
-                               debug("rtable->exlusive_irqs = %x\n",
+                                               (int) (*cur_slot)->device, i,
+                                               &irq_attr);
+
+                       debug("(*cur_slot)->irq[0] = %x\n",
+                                       (*cur_slot)->irq[0]);
+                       debug("(*cur_slot)->irq[1] = %x\n",
+                                       (*cur_slot)->irq[1]);
+                       debug("(*cur_slot)->irq[2] = %x\n",
+                                       (*cur_slot)->irq[2]);
+                       debug("(*cur_slot)->irq[3] = %x\n",
+                                       (*cur_slot)->irq[3]);
+
+                       debug("rtable->exlusive_irqs = %x\n",
                                        rtable->exclusive_irqs);
-                               debug("rtable->slots[loop].irq[0].bitmap = %x\n",
+                       debug("rtable->slots[loop].irq[0].bitmap = %x\n",
                                        rtable->slots[loop].irq[0].bitmap);
-                               debug("rtable->slots[loop].irq[1].bitmap = %x\n",
+                       debug("rtable->slots[loop].irq[1].bitmap = %x\n",
                                        rtable->slots[loop].irq[1].bitmap);
-                               debug("rtable->slots[loop].irq[2].bitmap = %x\n",
+                       debug("rtable->slots[loop].irq[2].bitmap = %x\n",
                                        rtable->slots[loop].irq[2].bitmap);
-                               debug("rtable->slots[loop].irq[3].bitmap = %x\n",
+                       debug("rtable->slots[loop].irq[3].bitmap = %x\n",
                                        rtable->slots[loop].irq[3].bitmap);
 
-                               debug("rtable->slots[loop].irq[0].link = %x\n",
+                       debug("rtable->slots[loop].irq[0].link = %x\n",
                                        rtable->slots[loop].irq[0].link);
-                               debug("rtable->slots[loop].irq[1].link = %x\n",
+                       debug("rtable->slots[loop].irq[1].link = %x\n",
                                        rtable->slots[loop].irq[1].link);
-                               debug("rtable->slots[loop].irq[2].link = %x\n",
+                       debug("rtable->slots[loop].irq[2].link = %x\n",
                                        rtable->slots[loop].irq[2].link);
-                               debug("rtable->slots[loop].irq[3].link = %x\n",
+                       debug("rtable->slots[loop].irq[3].link = %x\n",
                                        rtable->slots[loop].irq[3].link);
-                               debug("end of init_devno\n");
-                               kfree(rtable);
-                               return 0;
-                       }
+                       debug("end of init_devno\n");
+                       kfree(rtable);
+                       return 0;
                }
        }
 
index 6808d8333ecc414390590f83122f4c6602b01cef..737a1c44b07af9a8ed81ed6e2191fce7934603fd 100644 (file)
@@ -98,6 +98,7 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update)
        int max_irq;
        int pos;
        int irq;
+       int node;
 
        pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ);
        if (!pos)
@@ -125,7 +126,8 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update)
        cfg->msg.address_lo = 0xffffffff;
        cfg->msg.address_hi = 0xffffffff;
 
-       irq = create_irq();
+       node = dev_to_node(&dev->dev);
+       irq = create_irq_nr(0, node);
 
        if (irq <= 0) {
                kfree(cfg);
index a563fbe559d0505b90d1f736beb3a8e8bf197717..cd389162735f3f9ff03dd596d549134ae052de5a 100644 (file)
@@ -1972,15 +1972,6 @@ static int __init init_dmars(void)
                }
        }
 
-#ifdef CONFIG_INTR_REMAP
-       if (!intr_remapping_enabled) {
-               ret = enable_intr_remapping(0);
-               if (ret)
-                       printk(KERN_ERR
-                              "IOMMU: enable interrupt remapping failed\n");
-       }
-#endif
-
        /*
         * For each rmrr
         *   for each dev attached to rmrr
index f5e0ea724a6f53a12d26443fba84b01ab898f35d..3a0cb0bb05933bd72277df67af0cfe2254a7b6e4 100644 (file)
@@ -15,6 +15,14 @@ static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
 static int ir_ioapic_num;
 int intr_remapping_enabled;
 
+static int disable_intremap;
+static __init int setup_nointremap(char *str)
+{
+       disable_intremap = 1;
+       return 0;
+}
+early_param("nointremap", setup_nointremap);
+
 struct irq_2_iommu {
        struct intel_iommu *iommu;
        u16 irte_index;
@@ -23,15 +31,12 @@ struct irq_2_iommu {
 };
 
 #ifdef CONFIG_GENERIC_HARDIRQS
-static struct irq_2_iommu *get_one_free_irq_2_iommu(int cpu)
+static struct irq_2_iommu *get_one_free_irq_2_iommu(int node)
 {
        struct irq_2_iommu *iommu;
-       int node;
-
-       node = cpu_to_node(cpu);
 
        iommu = kzalloc_node(sizeof(*iommu), GFP_ATOMIC, node);
-       printk(KERN_DEBUG "alloc irq_2_iommu on cpu %d node %d\n", cpu, node);
+       printk(KERN_DEBUG "alloc irq_2_iommu on node %d\n", node);
 
        return iommu;
 }
@@ -48,7 +53,7 @@ static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
        return desc->irq_2_iommu;
 }
 
-static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu)
+static struct irq_2_iommu *irq_2_iommu_alloc_node(unsigned int irq, int node)
 {
        struct irq_desc *desc;
        struct irq_2_iommu *irq_iommu;
@@ -56,7 +61,7 @@ static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu)
        /*
         * alloc irq desc if not allocated already.
         */
-       desc = irq_to_desc_alloc_cpu(irq, cpu);
+       desc = irq_to_desc_alloc_node(irq, node);
        if (!desc) {
                printk(KERN_INFO "can not get irq_desc for %d\n", irq);
                return NULL;
@@ -65,14 +70,14 @@ static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu)
        irq_iommu = desc->irq_2_iommu;
 
        if (!irq_iommu)
-               desc->irq_2_iommu = get_one_free_irq_2_iommu(cpu);
+               desc->irq_2_iommu = get_one_free_irq_2_iommu(node);
 
        return desc->irq_2_iommu;
 }
 
 static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq)
 {
-       return irq_2_iommu_alloc_cpu(irq, boot_cpu_id);
+       return irq_2_iommu_alloc_node(irq, cpu_to_node(boot_cpu_id));
 }
 
 #else /* !CONFIG_SPARSE_IRQ */
@@ -423,20 +428,6 @@ static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode)
                      readl, (sts & DMA_GSTS_IRTPS), sts);
        spin_unlock_irqrestore(&iommu->register_lock, flags);
 
-       if (mode == 0) {
-               spin_lock_irqsave(&iommu->register_lock, flags);
-
-               /* enable comaptiblity format interrupt pass through */
-               cmd = iommu->gcmd | DMA_GCMD_CFI;
-               iommu->gcmd |= DMA_GCMD_CFI;
-               writel(cmd, iommu->reg + DMAR_GCMD_REG);
-
-               IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
-                             readl, (sts & DMA_GSTS_CFIS), sts);
-
-               spin_unlock_irqrestore(&iommu->register_lock, flags);
-       }
-
        /*
         * global invalidation of interrupt entry cache before enabling
         * interrupt-remapping.
@@ -516,6 +507,23 @@ end:
        spin_unlock_irqrestore(&iommu->register_lock, flags);
 }
 
+int __init intr_remapping_supported(void)
+{
+       struct dmar_drhd_unit *drhd;
+
+       if (disable_intremap)
+               return 0;
+
+       for_each_drhd_unit(drhd) {
+               struct intel_iommu *iommu = drhd->iommu;
+
+               if (!ecap_ir_support(iommu->ecap))
+                       return 0;
+       }
+
+       return 1;
+}
+
 int __init enable_intr_remapping(int eim)
 {
        struct dmar_drhd_unit *drhd;
index adf17856bacc187a8216af9ded5ec3cf2ed2662b..7f207f335beca2c53d8120c3a4681ff139cb7282 100644 (file)
@@ -123,7 +123,7 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev,
        }
 
        flags = irq_flags(triggering, polarity, shareable);
-       irq = acpi_register_gsi(gsi, triggering, polarity);
+       irq = acpi_register_gsi(&dev->dev, gsi, triggering, polarity);
        if (irq >= 0)
                pcibios_penalize_isa_irq(irq, 1);
        else
index 4e9851fc1746369653fe7d74764d1fe7fa9bc09e..277d35d232fad9c070e34ad17b9b7b7a66346cf8 100644 (file)
@@ -692,7 +692,7 @@ 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
+       depends on PARISC || M68K || PPC || SUPERH32
        help
          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
index d1815272c4351b90bbd972a649c8f11a3bd49710..27a1be0cd4d467a1b3c4ba1d6ab501d3b4ea2fdf 100644 (file)
@@ -603,7 +603,7 @@ static void dasd_profile_end(struct dasd_block *block,
        if (dasd_profile_level != DASD_PROFILE_ON)
                return;
 
-       sectors = req->nr_sectors;
+       sectors = blk_rq_sectors(req);
        if (!cqr->buildclk || !cqr->startclk ||
            !cqr->stopclk || !cqr->endclk ||
            !sectors)
@@ -1613,15 +1613,6 @@ void dasd_block_clear_timer(struct dasd_block *block)
        del_timer(&block->timer);
 }
 
-/*
- * posts the buffer_cache about a finalized request
- */
-static inline void dasd_end_request(struct request *req, int error)
-{
-       if (__blk_end_request(req, error, blk_rq_bytes(req)))
-               BUG();
-}
-
 /*
  * Process finished error recovery ccw.
  */
@@ -1665,18 +1656,14 @@ static void __dasd_process_request_queue(struct dasd_block *block)
        if (basedev->state < DASD_STATE_READY)
                return;
        /* Now we try to fetch requests from the request queue */
-       while (!blk_queue_plugged(queue) &&
-              elv_next_request(queue)) {
-
-               req = elv_next_request(queue);
-
+       while (!blk_queue_plugged(queue) && (req = blk_peek_request(queue))) {
                if (basedev->features & DASD_FEATURE_READONLY &&
                    rq_data_dir(req) == WRITE) {
                        DBF_DEV_EVENT(DBF_ERR, basedev,
                                      "Rejecting write request %p",
                                      req);
-                       blkdev_dequeue_request(req);
-                       dasd_end_request(req, -EIO);
+                       blk_start_request(req);
+                       __blk_end_request_all(req, -EIO);
                        continue;
                }
                cqr = basedev->discipline->build_cp(basedev, block, req);
@@ -1704,8 +1691,8 @@ static void __dasd_process_request_queue(struct dasd_block *block)
                                      "CCW creation failed (rc=%ld) "
                                      "on request %p",
                                      PTR_ERR(cqr), req);
-                       blkdev_dequeue_request(req);
-                       dasd_end_request(req, -EIO);
+                       blk_start_request(req);
+                       __blk_end_request_all(req, -EIO);
                        continue;
                }
                /*
@@ -1714,7 +1701,7 @@ static void __dasd_process_request_queue(struct dasd_block *block)
                 */
                cqr->callback_data = (void *) req;
                cqr->status = DASD_CQR_FILLED;
-               blkdev_dequeue_request(req);
+               blk_start_request(req);
                list_add_tail(&cqr->blocklist, &block->ccw_queue);
                dasd_profile_start(block, cqr, req);
        }
@@ -1731,7 +1718,7 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr)
        status = cqr->block->base->discipline->free_cp(cqr, req);
        if (status <= 0)
                error = status ? status : -EIO;
-       dasd_end_request(req, error);
+       __blk_end_request_all(req, error);
 }
 
 /*
@@ -2003,7 +1990,7 @@ static void dasd_setup_queue(struct dasd_block *block)
 {
        int max;
 
-       blk_queue_hardsect_size(block->request_queue, block->bp_block);
+       blk_queue_logical_block_size(block->request_queue, block->bp_block);
        max = block->base->discipline->max_blocks << block->s2b_shift;
        blk_queue_max_sectors(block->request_queue, max);
        blk_queue_max_phys_segments(block->request_queue, -1L);
@@ -2038,10 +2025,8 @@ static void dasd_flush_request_queue(struct dasd_block *block)
                return;
 
        spin_lock_irq(&block->request_queue_lock);
-       while ((req = elv_next_request(block->request_queue))) {
-               blkdev_dequeue_request(req);
-               dasd_end_request(req, -EIO);
-       }
+       while ((req = blk_fetch_request(block->request_queue)))
+               __blk_end_request_all(req, -EIO);
        spin_unlock_irq(&block->request_queue_lock);
 }
 
index b9a7f77334468ff5afc4e34d59a6baffadb543ea..2efaddfae56088be5d25bf27e4f53991105ec070 100644 (file)
@@ -505,8 +505,9 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
                return ERR_PTR(-EINVAL);
        blksize = block->bp_block;
        /* Calculate record id of first and last block. */
-       first_rec = req->sector >> block->s2b_shift;
-       last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
+       first_rec = blk_rq_pos(req) >> block->s2b_shift;
+       last_rec =
+               (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift;
        /* Check struct bio and count the number of blocks for the request. */
        count = 0;
        rq_for_each_segment(bv, req, iter) {
index cb52da033f061ebbe853b90afaad65db31b7fed5..a41c94053e64be88f1179153be06156c313d9093 100644 (file)
@@ -2354,10 +2354,10 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
        blksize = block->bp_block;
        blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
        /* Calculate record id of first and last block. */
-       first_rec = first_trk = req->sector >> block->s2b_shift;
+       first_rec = first_trk = blk_rq_pos(req) >> block->s2b_shift;
        first_offs = sector_div(first_trk, blk_per_trk);
        last_rec = last_trk =
-               (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
+               (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift;
        last_offs = sector_div(last_trk, blk_per_trk);
        cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk);
 
@@ -2420,7 +2420,7 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
        private = (struct dasd_eckd_private *) cqr->block->base->private;
        blksize = cqr->block->bp_block;
        blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
-       recid = req->sector >> cqr->block->s2b_shift;
+       recid = blk_rq_pos(req) >> cqr->block->s2b_shift;
        ccw = cqr->cpaddr;
        /* Skip over define extent & locate record. */
        ccw++;
index a3eb6fd146731dad7ef87c9f1dbe28a72eb504da..8912358daa2fd0c3c6561b7469c5d2d23b5e1d5d 100644 (file)
@@ -270,8 +270,9 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
                return ERR_PTR(-EINVAL);
        blksize = block->bp_block;
        /* Calculate record id of first and last block. */
-       first_rec = req->sector >> block->s2b_shift;
-       last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
+       first_rec = blk_rq_pos(req) >> block->s2b_shift;
+       last_rec =
+               (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift;
        /* Check struct bio and count the number of blocks for the request. */
        count = 0;
        cidaw = 0;
@@ -309,7 +310,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
        ccw = cqr->cpaddr;
        /* First ccw is define extent. */
        define_extent(ccw++, cqr->data, rq_data_dir(req),
-                     block->bp_block, req->sector, req->nr_sectors);
+                     block->bp_block, blk_rq_pos(req), blk_rq_sectors(req));
        /* Build locate_record + read/write ccws. */
        idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data));
        LO_data = (struct LO_fba_data *) (idaws + cidaw);
index cfdcf1aed33c282115e50cf2d6dddd0b96ff5b42..a4c7ffcd9987adb6dcec33687181597c84662ec9 100644 (file)
@@ -602,7 +602,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
        dev_info->gd->private_data = dev_info;
        dev_info->gd->driverfs_dev = &dev_info->dev;
        blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);
-       blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
+       blk_queue_logical_block_size(dev_info->dcssblk_queue, 4096);
 
        seg_byte_size = (dev_info->end - dev_info->start + 1);
        set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors
index 76814f3e898a9c444dca70b4ddfc0cd7d885847c..0ae0c83ef87903e9121b76e14ae372dd2e40b8d1 100644 (file)
@@ -343,7 +343,7 @@ static int __init xpram_setup_blkdev(void)
                        goto out;
                }
                blk_queue_make_request(xpram_queues[i], xpram_make_request);
-               blk_queue_hardsect_size(xpram_queues[i], 4096);
+               blk_queue_logical_block_size(xpram_queues[i], 4096);
        }
 
        /*
index 5f8e8ef43dd312add6ca69cc9ed851a903e38c3b..2d00a383a475ca50fbc93a6b0fee0cc1df018c59 100644 (file)
@@ -1134,7 +1134,7 @@ tape_34xx_bread(struct tape_device *device, struct request *req)
        /* Setup ccws. */
        request->op = TO_BLOCK;
        start_block = (struct tape_34xx_block_id *) request->cpdata;
-       start_block->block = req->sector >> TAPEBLOCK_HSEC_S2B;
+       start_block->block = blk_rq_pos(req) >> TAPEBLOCK_HSEC_S2B;
        DBF_EVENT(6, "start_block = %i\n", start_block->block);
 
        ccw = request->cpaddr;
index 823b05bd0dd79d9ab928d214b36cab9ec78626df..c453b2f3e9f4c6c46cf73a9be1397c9f10873c7c 100644 (file)
@@ -633,7 +633,7 @@ tape_3590_bread(struct tape_device *device, struct request *req)
        struct req_iterator iter;
 
        DBF_EVENT(6, "xBREDid:");
-       start_block = req->sector >> TAPEBLOCK_HSEC_S2B;
+       start_block = blk_rq_pos(req) >> TAPEBLOCK_HSEC_S2B;
        DBF_EVENT(6, "start_block = %i\n", start_block);
 
        rq_for_each_segment(bv, req, iter)
index f32e89e7c4f2e9f3f1aa54856996c446921e8a9a..47ff695255ea649f1f0296ed7f6f602ee1d4f9ac 100644 (file)
@@ -73,13 +73,6 @@ tapeblock_trigger_requeue(struct tape_device *device)
 /*
  * Post finished request.
  */
-static void
-tapeblock_end_request(struct request *req, int error)
-{
-       if (blk_end_request(req, error, blk_rq_bytes(req)))
-               BUG();
-}
-
 static void
 __tapeblock_end_request(struct tape_request *ccw_req, void *data)
 {
@@ -90,17 +83,17 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data)
 
        device = ccw_req->device;
        req = (struct request *) data;
-       tapeblock_end_request(req, (ccw_req->rc == 0) ? 0 : -EIO);
+       blk_end_request_all(req, (ccw_req->rc == 0) ? 0 : -EIO);
        if (ccw_req->rc == 0)
                /* Update position. */
                device->blk_data.block_position =
-                       (req->sector + req->nr_sectors) >> TAPEBLOCK_HSEC_S2B;
+                 (blk_rq_pos(req) + blk_rq_sectors(req)) >> TAPEBLOCK_HSEC_S2B;
        else
                /* We lost the position information due to an error. */
                device->blk_data.block_position = -1;
        device->discipline->free_bread(ccw_req);
        if (!list_empty(&device->req_queue) ||
-           elv_next_request(device->blk_data.request_queue))
+           blk_peek_request(device->blk_data.request_queue))
                tapeblock_trigger_requeue(device);
 }
 
@@ -118,7 +111,7 @@ tapeblock_start_request(struct tape_device *device, struct request *req)
        ccw_req = device->discipline->bread(device, req);
        if (IS_ERR(ccw_req)) {
                DBF_EVENT(1, "TBLOCK: bread failed\n");
-               tapeblock_end_request(req, -EIO);
+               blk_end_request_all(req, -EIO);
                return PTR_ERR(ccw_req);
        }
        ccw_req->callback = __tapeblock_end_request;
@@ -131,7 +124,7 @@ tapeblock_start_request(struct tape_device *device, struct request *req)
                 * Start/enqueueing failed. No retries in
                 * this case.
                 */
-               tapeblock_end_request(req, -EIO);
+               blk_end_request_all(req, -EIO);
                device->discipline->free_bread(ccw_req);
        }
 
@@ -169,19 +162,16 @@ tapeblock_requeue(struct work_struct *work) {
        spin_lock_irq(&device->blk_data.request_queue_lock);
        while (
                !blk_queue_plugged(queue) &&
-               elv_next_request(queue)   &&
+               (req = blk_fetch_request(queue)) &&
                nr_queued < TAPEBLOCK_MIN_REQUEUE
        ) {
-               req = elv_next_request(queue);
                if (rq_data_dir(req) == WRITE) {
                        DBF_EVENT(1, "TBLOCK: Rejecting write request\n");
-                       blkdev_dequeue_request(req);
                        spin_unlock_irq(&device->blk_data.request_queue_lock);
-                       tapeblock_end_request(req, -EIO);
+                       blk_end_request_all(req, -EIO);
                        spin_lock_irq(&device->blk_data.request_queue_lock);
                        continue;
                }
-               blkdev_dequeue_request(req);
                nr_queued++;
                spin_unlock_irq(&device->blk_data.request_queue_lock);
                rc = tapeblock_start_request(device, req);
@@ -232,7 +222,7 @@ tapeblock_setup_device(struct tape_device * device)
        if (rc)
                goto cleanup_queue;
 
-       blk_queue_hardsect_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE);
+       blk_queue_logical_block_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE);
        blk_queue_max_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC);
        blk_queue_max_phys_segments(blkdat->request_queue, -1L);
        blk_queue_max_hw_segments(blkdat->request_queue, -1L);
index a85ad05e85482a96d774358123b88e3401a50d0b..6d46516846884515bd56b35a9f0d28b342df1b03 100644 (file)
@@ -186,31 +186,31 @@ static void jsfd_do_request(struct request_queue *q)
 {
        struct request *req;
 
-       while ((req = elv_next_request(q)) != NULL) {
+       req = blk_fetch_request(q);
+       while (req) {
                struct jsfd_part *jdp = req->rq_disk->private_data;
-               unsigned long offset = req->sector << 9;
-               size_t len = req->current_nr_sectors << 9;
+               unsigned long offset = blk_rq_pos(req) << 9;
+               size_t len = blk_rq_cur_bytes(req);
+               int err = -EIO;
 
-               if ((offset + len) > jdp->dsize) {
-                               end_request(req, 0);
-                       continue;
-               }
+               if ((offset + len) > jdp->dsize)
+                       goto end;
 
                if (rq_data_dir(req) != READ) {
                        printk(KERN_ERR "jsfd: write\n");
-                       end_request(req, 0);
-                       continue;
+                       goto end;
                }
 
                if ((jdp->dbase & 0xff000000) != 0x20000000) {
                        printk(KERN_ERR "jsfd: bad base %x\n", (int)jdp->dbase);
-                       end_request(req, 0);
-                       continue;
+                       goto end;
                }
 
                jsfd_read(req->buffer, jdp->dbase + offset, len);
-
-               end_request(req, 1);
+               err = 0;
+       end:
+               if (!__blk_end_request_cur(req, err))
+                       req = blk_fetch_request(q);
        }
 }
 
index be5099dd94b5d4e655385ad59364dbd585da1910..c7076ce25e2121dcad840347314cea0ac2997890 100644 (file)
@@ -1825,7 +1825,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
        if (linked_comm && SCpnt->device->queue_depth > 2
            && TLDEV(SCpnt->device->type)) {
                ha->cp_stat[i] = READY;
-               flush_dev(SCpnt->device, SCpnt->request->sector, ha, 0);
+               flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), ha, 0);
                return 0;
        }
 
@@ -2144,13 +2144,13 @@ static int reorder(struct hostdata *ha, unsigned long cursec,
                if (!cpp->din)
                        input_only = 0;
 
-               if (SCpnt->request->sector < minsec)
-                       minsec = SCpnt->request->sector;
-               if (SCpnt->request->sector > maxsec)
-                       maxsec = SCpnt->request->sector;
+               if (blk_rq_pos(SCpnt->request) < minsec)
+                       minsec = blk_rq_pos(SCpnt->request);
+               if (blk_rq_pos(SCpnt->request) > maxsec)
+                       maxsec = blk_rq_pos(SCpnt->request);
 
-               sl[n] = SCpnt->request->sector;
-               ioseek += SCpnt->request->nr_sectors;
+               sl[n] = blk_rq_pos(SCpnt->request);
+               ioseek += blk_rq_sectors(SCpnt->request);
 
                if (!n)
                        continue;
@@ -2190,7 +2190,7 @@ static int reorder(struct hostdata *ha, unsigned long cursec,
                        k = il[n];
                        cpp = &ha->cp[k];
                        SCpnt = cpp->SCpnt;
-                       ll[n] = SCpnt->request->nr_sectors;
+                       ll[n] = blk_rq_sectors(SCpnt->request);
                        pl[n] = SCpnt->serial_number;
 
                        if (!n)
@@ -2236,12 +2236,12 @@ static int reorder(struct hostdata *ha, unsigned long cursec,
                        cpp = &ha->cp[k];
                        SCpnt = cpp->SCpnt;
                        scmd_printk(KERN_INFO, SCpnt,
-                           "%s pid %ld mb %d fc %d nr %d sec %ld ns %ld"
+                           "%s pid %ld mb %d fc %d nr %d sec %ld ns %u"
                             " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
                             (ihdlr ? "ihdlr" : "qcomm"),
                             SCpnt->serial_number, k, flushcount,
-                            n_ready, SCpnt->request->sector,
-                            SCpnt->request->nr_sectors, cursec, YESNO(s),
+                            n_ready, blk_rq_pos(SCpnt->request),
+                            blk_rq_sectors(SCpnt->request), cursec, YESNO(s),
                             YESNO(r), YESNO(rev), YESNO(input_only),
                             YESNO(overlap), cpp->din);
                }
@@ -2408,7 +2408,7 @@ static irqreturn_t ihdlr(struct Scsi_Host *shost)
 
        if (linked_comm && SCpnt->device->queue_depth > 2
            && TLDEV(SCpnt->device->type))
-               flush_dev(SCpnt->device, SCpnt->request->sector, ha, 1);
+               flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), ha, 1);
 
        tstatus = status_byte(spp->target_status);
 
index 3da02e4367884b4f8fcc1015811b55b0bf88a968..54fa1e42dc4d2dfba29cdf52afd52d909af67139 100644 (file)
@@ -1927,21 +1927,21 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        /* do we need to support multiple segments? */
        if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
                printk("%s: multiple segments req %u %u, rsp %u %u\n",
-                      __func__, req->bio->bi_vcnt, req->data_len,
-                      rsp->bio->bi_vcnt, rsp->data_len);
+                      __func__, req->bio->bi_vcnt, blk_rq_bytes(req),
+                      rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
                return -EINVAL;
        }
 
-       ret = smp_execute_task(dev, bio_data(req->bio), req->data_len,
-                              bio_data(rsp->bio), rsp->data_len);
+       ret = smp_execute_task(dev, bio_data(req->bio), blk_rq_bytes(req),
+                              bio_data(rsp->bio), blk_rq_bytes(rsp));
        if (ret > 0) {
                /* positive number is the untransferred residual */
-               rsp->data_len = ret;
-               req->data_len = 0;
+               rsp->resid_len = ret;
+               req->resid_len = 0;
                ret = 0;
        } else if (ret == 0) {
-               rsp->data_len = 0;
-               req->data_len = 0;
+               rsp->resid_len = 0;
+               req->resid_len = 0;
        }
 
        return ret;
index d110a366c48a13f7e8372ac81c1a15de05c40efa..1bc3b75679947ac1d8bcca33d132835cf16854f8 100644 (file)
@@ -134,24 +134,24 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
 {
        u8 *req_data = NULL, *resp_data = NULL, *buf;
        struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
-       int error = -EINVAL, resp_data_len = rsp->data_len;
+       int error = -EINVAL;
 
        /* eight is the minimum size for request and response frames */
-       if (req->data_len < 8 || rsp->data_len < 8)
+       if (blk_rq_bytes(req) < 8 || blk_rq_bytes(rsp) < 8)
                goto out;
 
-       if (bio_offset(req->bio) + req->data_len > PAGE_SIZE ||
-           bio_offset(rsp->bio) + rsp->data_len > PAGE_SIZE) {
+       if (bio_offset(req->bio) + blk_rq_bytes(req) > PAGE_SIZE ||
+           bio_offset(rsp->bio) + blk_rq_bytes(rsp) > PAGE_SIZE) {
                shost_printk(KERN_ERR, shost,
                        "SMP request/response frame crosses page boundary");
                goto out;
        }
 
-       req_data = kzalloc(req->data_len, GFP_KERNEL);
+       req_data = kzalloc(blk_rq_bytes(req), GFP_KERNEL);
 
        /* make sure frame can always be built ... we copy
         * back only the requested length */
-       resp_data = kzalloc(max(rsp->data_len, 128U), GFP_KERNEL);
+       resp_data = kzalloc(max(blk_rq_bytes(rsp), 128U), GFP_KERNEL);
 
        if (!req_data || !resp_data) {
                error = -ENOMEM;
@@ -160,7 +160,7 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
 
        local_irq_disable();
        buf = kmap_atomic(bio_page(req->bio), KM_USER0) + bio_offset(req->bio);
-       memcpy(req_data, buf, req->data_len);
+       memcpy(req_data, buf, blk_rq_bytes(req));
        kunmap_atomic(buf - bio_offset(req->bio), KM_USER0);
        local_irq_enable();
 
@@ -178,15 +178,15 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
 
        switch (req_data[1]) {
        case SMP_REPORT_GENERAL:
-               req->data_len -= 8;
-               resp_data_len -= 32;
+               req->resid_len -= 8;
+               rsp->resid_len -= 32;
                resp_data[2] = SMP_RESP_FUNC_ACC;
                resp_data[9] = sas_ha->num_phys;
                break;
 
        case SMP_REPORT_MANUF_INFO:
-               req->data_len -= 8;
-               resp_data_len -= 64;
+               req->resid_len -= 8;
+               rsp->resid_len -= 64;
                resp_data[2] = SMP_RESP_FUNC_ACC;
                memcpy(resp_data + 12, shost->hostt->name,
                       SAS_EXPANDER_VENDOR_ID_LEN);
@@ -199,13 +199,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
                break;
 
        case SMP_DISCOVER:
-               req->data_len -= 16;
-               if ((int)req->data_len < 0) {
-                       req->data_len = 0;
+               req->resid_len -= 16;
+               if ((int)req->resid_len < 0) {
+                       req->resid_len = 0;
                        error = -EINVAL;
                        goto out;
                }
-               resp_data_len -= 56;
+               rsp->resid_len -= 56;
                sas_host_smp_discover(sas_ha, resp_data, req_data[9]);
                break;
 
@@ -215,13 +215,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
                break;
 
        case SMP_REPORT_PHY_SATA:
-               req->data_len -= 16;
-               if ((int)req->data_len < 0) {
-                       req->data_len = 0;
+               req->resid_len -= 16;
+               if ((int)req->resid_len < 0) {
+                       req->resid_len = 0;
                        error = -EINVAL;
                        goto out;
                }
-               resp_data_len -= 60;
+               rsp->resid_len -= 60;
                sas_report_phy_sata(sas_ha, resp_data, req_data[9]);
                break;
 
@@ -238,13 +238,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
                break;
 
        case SMP_PHY_CONTROL:
-               req->data_len -= 44;
-               if ((int)req->data_len < 0) {
-                       req->data_len = 0;
+               req->resid_len -= 44;
+               if ((int)req->resid_len < 0) {
+                       req->resid_len = 0;
                        error = -EINVAL;
                        goto out;
                }
-               resp_data_len -= 8;
+               rsp->resid_len -= 8;
                sas_phy_control(sas_ha, req_data[9], req_data[10],
                                req_data[32] >> 4, req_data[33] >> 4,
                                resp_data);
@@ -261,11 +261,10 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
 
        local_irq_disable();
        buf = kmap_atomic(bio_page(rsp->bio), KM_USER0) + bio_offset(rsp->bio);
-       memcpy(buf, resp_data, rsp->data_len);
+       memcpy(buf, resp_data, blk_rq_bytes(rsp));
        flush_kernel_dcache_page(bio_page(rsp->bio));
        kunmap_atomic(buf - bio_offset(rsp->bio), KM_USER0);
        local_irq_enable();
-       rsp->data_len = resp_data_len;
 
  out:
        kfree(req_data);
index 167b66dd34c712a73d103d26f603d87042ae4cd7..8032c5adb6a9b2400c318912a7aa376df512b096 100644 (file)
@@ -1312,10 +1312,10 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
        uint32_t bgstat = bgf->bgstat;
        uint64_t failing_sector = 0;
 
-       printk(KERN_ERR "BG ERROR in cmd 0x%x lba 0x%llx blk cnt 0x%lx "
+       printk(KERN_ERR "BG ERROR in cmd 0x%x lba 0x%llx blk cnt 0x%x "
                        "bgstat=0x%x bghm=0x%x\n",
                        cmd->cmnd[0], (unsigned long long)scsi_get_lba(cmd),
-                       cmd->request->nr_sectors, bgstat, bghm);
+                       blk_rq_sectors(cmd->request), bgstat, bghm);
 
        spin_lock(&_dump_buf_lock);
        if (!_dump_buf_done) {
@@ -2378,15 +2378,15 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
                if (cmnd->cmnd[0] == READ_10)
                        lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
                                        "9035 BLKGRD: READ @ sector %llu, "
-                                        "count %lu\n",
-                                        (unsigned long long)scsi_get_lba(cmnd),
-                                       cmnd->request->nr_sectors);
+                                       "count %u\n",
+                                       (unsigned long long)scsi_get_lba(cmnd),
+                                       blk_rq_sectors(cmnd->request));
                else if (cmnd->cmnd[0] == WRITE_10)
                        lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
                                        "9036 BLKGRD: WRITE @ sector %llu, "
-                                       "count %lu cmd=%p\n",
+                                       "count %u cmd=%p\n",
                                        (unsigned long long)scsi_get_lba(cmnd),
-                                       cmnd->request->nr_sectors,
+                                       blk_rq_sectors(cmnd->request),
                                        cmnd);
 
                err = lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd);
@@ -2406,15 +2406,15 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
                if (cmnd->cmnd[0] == READ_10)
                        lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
                                         "9040 dbg: READ @ sector %llu, "
-                                        "count %lu\n",
+                                        "count %u\n",
                                         (unsigned long long)scsi_get_lba(cmnd),
-                                        cmnd->request->nr_sectors);
+                                        blk_rq_sectors(cmnd->request));
                else if (cmnd->cmnd[0] == WRITE_10)
                        lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
                                         "9041 dbg: WRITE @ sector %llu, "
-                                        "count %lu cmd=%p\n",
+                                        "count %u cmd=%p\n",
                                         (unsigned long long)scsi_get_lba(cmnd),
-                                        cmnd->request->nr_sectors, cmnd);
+                                        blk_rq_sectors(cmnd->request), cmnd);
                else
                        lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
                                         "9042 dbg: parser not implemented\n");
index e03dc0b1e1a0f906d1393fbc82a0157f9e2ee49e..5c65da519e39af511334816c18977912a4920637 100644 (file)
@@ -1041,7 +1041,7 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
                printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, "
                    "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt,
-                   req->data_len, rsp->bio->bi_vcnt, rsp->data_len);
+                   blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
                return -EINVAL;
        }
 
@@ -1104,7 +1104,7 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        *((u64 *)&mpi_request->SASAddress) = (rphy) ?
            cpu_to_le64(rphy->identify.sas_address) :
            cpu_to_le64(ioc->sas_hba.sas_address);
-       mpi_request->RequestDataLength = cpu_to_le16(req->data_len - 4);
+       mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
        psge = &mpi_request->SGL;
 
        /* WRITE sgel first */
@@ -1112,13 +1112,13 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
            MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
        sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
        dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
-             req->data_len, PCI_DMA_BIDIRECTIONAL);
+               blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
        if (!dma_addr_out) {
                mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
                goto unmap;
        }
 
-       ioc->base_add_sg_single(psge, sgl_flags | (req->data_len - 4),
+       ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4),
            dma_addr_out);
 
        /* incr sgel */
@@ -1129,14 +1129,14 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
            MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
            MPI2_SGE_FLAGS_END_OF_LIST);
        sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
-       dma_addr_in =  pci_map_single(ioc->pdev, bio_data(rsp->bio),
-             rsp->data_len, PCI_DMA_BIDIRECTIONAL);
+       dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
+                                    blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
        if (!dma_addr_in) {
                mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
                goto unmap;
        }
 
-       ioc->base_add_sg_single(psge, sgl_flags | (rsp->data_len + 4),
+       ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4),
            dma_addr_in);
 
        dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
@@ -1170,9 +1170,8 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
                memcpy(req->sense, mpi_reply, sizeof(*mpi_reply));
                req->sense_len = sizeof(*mpi_reply);
-               req->data_len = 0;
-               rsp->data_len -= mpi_reply->ResponseDataLength;
-
+               req->resid_len = 0;
+               rsp->resid_len -= mpi_reply->ResponseDataLength;
        } else {
                dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
                    "%s - no reply\n", ioc->name, __func__));
@@ -1188,10 +1187,10 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
  unmap:
        if (dma_addr_out)
-               pci_unmap_single(ioc->pdev, dma_addr_out, req->data_len,
+               pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req),
                    PCI_DMA_BIDIRECTIONAL);
        if (dma_addr_in)
-               pci_unmap_single(ioc->pdev, dma_addr_in, rsp->data_len,
+               pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp),
                    PCI_DMA_BIDIRECTIONAL);
 
  out:
index 1ce6b24abab297f70937a43cfd414bbe60349f26..5776b2ab6b12a5fa54fe974b11e31619d8ee18e0 100644 (file)
@@ -889,26 +889,6 @@ int osd_req_add_set_attr_list(struct osd_request *or,
 }
 EXPORT_SYMBOL(osd_req_add_set_attr_list);
 
-static int _append_map_kern(struct request *req,
-       void *buff, unsigned len, gfp_t flags)
-{
-       struct bio *bio;
-       int ret;
-
-       bio = bio_map_kern(req->q, buff, len, flags);
-       if (IS_ERR(bio)) {
-               OSD_ERR("Failed bio_map_kern(%p, %d) => %ld\n", buff, len,
-                       PTR_ERR(bio));
-               return PTR_ERR(bio);
-       }
-       ret = blk_rq_append_bio(req->q, req, bio);
-       if (ret) {
-               OSD_ERR("Failed blk_rq_append_bio(%p) => %d\n", bio, ret);
-               bio_put(bio);
-       }
-       return ret;
-}
-
 static int _req_append_segment(struct osd_request *or,
        unsigned padding, struct _osd_req_data_segment *seg,
        struct _osd_req_data_segment *last_seg, struct _osd_io_info *io)
@@ -924,14 +904,14 @@ static int _req_append_segment(struct osd_request *or,
                else
                        pad_buff = io->pad_buff;
 
-               ret = _append_map_kern(io->req, pad_buff, padding,
+               ret = blk_rq_map_kern(io->req->q, io->req, pad_buff, padding,
                                       or->alloc_flags);
                if (ret)
                        return ret;
                io->total_bytes += padding;
        }
 
-       ret = _append_map_kern(io->req, seg->buff, seg->total_bytes,
+       ret = blk_rq_map_kern(io->req->q, io->req, seg->buff, seg->total_bytes,
                               or->alloc_flags);
        if (ret)
                return ret;
@@ -1293,6 +1273,21 @@ static int _osd_req_finalize_data_integrity(struct osd_request *or,
 /*
  * osd_finalize_request and helpers
  */
+static struct request *_make_request(struct request_queue *q, bool has_write,
+                             struct _osd_io_info *oii, gfp_t flags)
+{
+       if (oii->bio)
+               return blk_make_request(q, oii->bio, flags);
+       else {
+               struct request *req;
+
+               req = blk_get_request(q, has_write ? WRITE : READ, flags);
+               if (unlikely(!req))
+                       return ERR_PTR(-ENOMEM);
+
+               return req;
+       }
+}
 
 static int _init_blk_request(struct osd_request *or,
        bool has_in, bool has_out)
@@ -1301,11 +1296,13 @@ static int _init_blk_request(struct osd_request *or,
        struct scsi_device *scsi_device = or->osd_dev->scsi_device;
        struct request_queue *q = scsi_device->request_queue;
        struct request *req;
-       int ret = -ENOMEM;
+       int ret;
 
-       req = blk_get_request(q, has_out, flags);
-       if (!req)
+       req = _make_request(q, has_out, has_out ? &or->out : &or->in, flags);
+       if (IS_ERR(req)) {
+               ret = PTR_ERR(req);
                goto out;
+       }
 
        or->request = req;
        req->cmd_type = REQ_TYPE_BLOCK_PC;
@@ -1318,9 +1315,10 @@ static int _init_blk_request(struct osd_request *or,
                or->out.req = req;
                if (has_in) {
                        /* allocate bidi request */
-                       req = blk_get_request(q, READ, flags);
-                       if (!req) {
+                       req = _make_request(q, false, &or->in, flags);
+                       if (IS_ERR(req)) {
                                OSD_DEBUG("blk_get_request for bidi failed\n");
+                               ret = PTR_ERR(req);
                                goto out;
                        }
                        req->cmd_type = REQ_TYPE_BLOCK_PC;
@@ -1364,26 +1362,6 @@ int osd_finalize_request(struct osd_request *or,
                return ret;
        }
 
-       if (or->out.bio) {
-               ret = blk_rq_append_bio(or->request->q, or->out.req,
-                                       or->out.bio);
-               if (ret) {
-                       OSD_DEBUG("blk_rq_append_bio out failed\n");
-                       return ret;
-               }
-               OSD_DEBUG("out bytes=%llu (bytes_req=%u)\n",
-                       _LLU(or->out.total_bytes), or->out.req->data_len);
-       }
-       if (or->in.bio) {
-               ret = blk_rq_append_bio(or->request->q, or->in.req, or->in.bio);
-               if (ret) {
-                       OSD_DEBUG("blk_rq_append_bio in failed\n");
-                       return ret;
-               }
-               OSD_DEBUG("in bytes=%llu (bytes_req=%u)\n",
-                       _LLU(or->in.total_bytes), or->in.req->data_len);
-       }
-
        or->out.pad_buff = sg_out_pad_buffer;
        or->in.pad_buff = sg_in_pad_buffer;
 
index bb218c8b6e98373344d1c188982a189a7aecbbf9..dd3f9d2b99fd05b7834e0abbb7e2cbe23e12d462 100644 (file)
@@ -240,11 +240,11 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
         * is invalid.  Prevent the garbage from being misinterpreted
         * and prevent security leaks by zeroing out the excess data.
         */
-       if (unlikely(req->data_len > 0 && req->data_len <= bufflen))
-               memset(buffer + (bufflen - req->data_len), 0, req->data_len);
+       if (unlikely(req->resid_len > 0 && req->resid_len <= bufflen))
+               memset(buffer + (bufflen - req->resid_len), 0, req->resid_len);
 
        if (resid)
-               *resid = req->data_len;
+               *resid = req->resid_len;
        ret = req->errors;
  out:
        blk_put_request(req);
@@ -546,14 +546,9 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error,
         * to queue the remainder of them.
         */
        if (blk_end_request(req, error, bytes)) {
-               int leftover = (req->hard_nr_sectors << 9);
-
-               if (blk_pc_request(req))
-                       leftover = req->data_len;
-
                /* kill remainder if no retrys */
                if (error && scsi_noretry_cmd(cmd))
-                       blk_end_request(req, error, leftover);
+                       blk_end_request_all(req, error);
                else {
                        if (requeue) {
                                /*
@@ -672,34 +667,6 @@ void scsi_release_buffers(struct scsi_cmnd *cmd)
 }
 EXPORT_SYMBOL(scsi_release_buffers);
 
-/*
- * Bidi commands Must be complete as a whole, both sides at once.
- * If part of the bytes were written and lld returned
- * scsi_in()->resid and/or scsi_out()->resid this information will be left
- * in req->data_len and req->next_rq->data_len. The upper-layer driver can
- * decide what to do with this information.
- */
-static void scsi_end_bidi_request(struct scsi_cmnd *cmd)
-{
-       struct request *req = cmd->request;
-       unsigned int dlen = req->data_len;
-       unsigned int next_dlen = req->next_rq->data_len;
-
-       req->data_len = scsi_out(cmd)->resid;
-       req->next_rq->data_len = scsi_in(cmd)->resid;
-
-       /* The req and req->next_rq have not been completed */
-       BUG_ON(blk_end_bidi_request(req, 0, dlen, next_dlen));
-
-       scsi_release_buffers(cmd);
-
-       /*
-        * This will goose the queue request function at the end, so we don't
-        * need to worry about launching another command.
-        */
-       scsi_next_command(cmd);
-}
-
 /*
  * Function:    scsi_io_completion()
  *
@@ -739,7 +706,6 @@ static void scsi_end_bidi_request(struct scsi_cmnd *cmd)
 void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 {
        int result = cmd->result;
-       int this_count;
        struct request_queue *q = cmd->device->request_queue;
        struct request *req = cmd->request;
        int error = 0;
@@ -773,12 +739,22 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                        if (!sense_deferred)
                                error = -EIO;
                }
+
+               req->resid_len = scsi_get_resid(cmd);
+
                if (scsi_bidi_cmnd(cmd)) {
-                       /* will also release_buffers */
-                       scsi_end_bidi_request(cmd);
+                       /*
+                        * Bidi commands Must be complete as a whole,
+                        * both sides at once.
+                        */
+                       req->next_rq->resid_len = scsi_in(cmd)->resid;
+
+                       blk_end_request_all(req, 0);
+
+                       scsi_release_buffers(cmd);
+                       scsi_next_command(cmd);
                        return;
                }
-               req->data_len = scsi_get_resid(cmd);
        }
 
        BUG_ON(blk_bidi_rq(req)); /* bidi not support for !blk_pc_request yet */
@@ -787,9 +763,9 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
         * Next deal with any sectors which we were able to correctly
         * handle.
         */
-       SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, "
+       SCSI_LOG_HLCOMPLETE(1, printk("%u sectors total, "
                                      "%d bytes done.\n",
-                                     req->nr_sectors, good_bytes));
+                                     blk_rq_sectors(req), good_bytes));
 
        /*
         * Recovered errors need reporting, but they're always treated
@@ -812,7 +788,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
         */
        if (scsi_end_request(cmd, error, good_bytes, result == 0) == NULL)
                return;
-       this_count = blk_rq_bytes(req);
 
        error = -EIO;
 
@@ -922,7 +897,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                        if (driver_byte(result) & DRIVER_SENSE)
                                scsi_print_sense("", cmd);
                }
-               blk_end_request(req, -EIO, blk_rq_bytes(req));
+               blk_end_request_all(req, -EIO);
                scsi_next_command(cmd);
                break;
        case ACTION_REPREP:
@@ -965,10 +940,7 @@ static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb,
        count = blk_rq_map_sg(req->q, req, sdb->table.sgl);
        BUG_ON(count > sdb->table.nents);
        sdb->table.nents = count;
-       if (blk_pc_request(req))
-               sdb->length = req->data_len;
-       else
-               sdb->length = req->nr_sectors << 9;
+       sdb->length = blk_rq_bytes(req);
        return BLKPREP_OK;
 }
 
@@ -1087,22 +1059,21 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
                if (unlikely(ret))
                        return ret;
        } else {
-               BUG_ON(req->data_len);
-               BUG_ON(req->data);
+               BUG_ON(blk_rq_bytes(req));
 
                memset(&cmd->sdb, 0, sizeof(cmd->sdb));
                req->buffer = NULL;
        }
 
        cmd->cmd_len = req->cmd_len;
-       if (!req->data_len)
+       if (!blk_rq_bytes(req))
                cmd->sc_data_direction = DMA_NONE;
        else if (rq_data_dir(req) == WRITE)
                cmd->sc_data_direction = DMA_TO_DEVICE;
        else
                cmd->sc_data_direction = DMA_FROM_DEVICE;
        
-       cmd->transfersize = req->data_len;
+       cmd->transfersize = blk_rq_bytes(req);
        cmd->allowed = req->retries;
        return BLKPREP_OK;
 }
@@ -1212,7 +1183,7 @@ int scsi_prep_return(struct request_queue *q, struct request *req, int ret)
                break;
        case BLKPREP_DEFER:
                /*
-                * If we defer, the elv_next_request() returns NULL, but the
+                * If we defer, the blk_peek_request() returns NULL, but the
                 * queue must be restarted, so we plug here if no returning
                 * command will automatically do that.
                 */
@@ -1388,7 +1359,7 @@ static void scsi_kill_request(struct request *req, struct request_queue *q)
        struct scsi_target *starget = scsi_target(sdev);
        struct Scsi_Host *shost = sdev->host;
 
-       blkdev_dequeue_request(req);
+       blk_start_request(req);
 
        if (unlikely(cmd == NULL)) {
                printk(KERN_CRIT "impossible request in %s.\n",
@@ -1480,7 +1451,7 @@ static void scsi_request_fn(struct request_queue *q)
 
        if (!sdev) {
                printk("scsi: killing requests for dead queue\n");
-               while ((req = elv_next_request(q)) != NULL)
+               while ((req = blk_peek_request(q)) != NULL)
                        scsi_kill_request(req, q);
                return;
        }
@@ -1501,7 +1472,7 @@ static void scsi_request_fn(struct request_queue *q)
                 * that the request is fully prepared even if we cannot 
                 * accept it.
                 */
-               req = elv_next_request(q);
+               req = blk_peek_request(q);
                if (!req || !scsi_dev_queue_ready(q, sdev))
                        break;
 
@@ -1517,7 +1488,7 @@ static void scsi_request_fn(struct request_queue *q)
                 * Remove the request from the request list.
                 */
                if (!(blk_queue_tagged(q) && !blk_queue_start_tag(q, req)))
-                       blkdev_dequeue_request(req);
+                       blk_start_request(req);
                sdev->device_busy++;
 
                spin_unlock(q->queue_lock);
index 48ba413f7f6afb511f9d0c26daa42a5cb34dce77..10303272ba4573082f942a4ec8e9cd7e4d0a9e95 100644 (file)
@@ -387,7 +387,7 @@ static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd,
         * we use REQ_TYPE_BLOCK_PC so scsi_init_io doesn't set the
         * length for us.
         */
-       cmd->sdb.length = rq->data_len;
+       cmd->sdb.length = blk_rq_bytes(rq);
 
        return 0;
 
index 50988cbf7b2df90a1cc23d07e423c920b428e2ba..d606452297cf3fdc82747b279067fb67613f8779 100644 (file)
@@ -163,12 +163,10 @@ static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
        int (*handler)(struct Scsi_Host *, struct sas_rphy *, struct request *);
 
        while (!blk_queue_plugged(q)) {
-               req = elv_next_request(q);
+               req = blk_fetch_request(q);
                if (!req)
                        break;
 
-               blkdev_dequeue_request(req);
-
                spin_unlock_irq(q->queue_lock);
 
                handler = to_sas_internal(shost->transportt)->f->smp_handler;
index 84044233b637c71929bf22b665d15976096e5d63..bcf3bd40bbd5fc3bfbecb29f0d7b21b5e393c8b3 100644 (file)
@@ -384,9 +384,9 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
        struct scsi_device *sdp = q->queuedata;
        struct gendisk *disk = rq->rq_disk;
        struct scsi_disk *sdkp;
-       sector_t block = rq->sector;
+       sector_t block = blk_rq_pos(rq);
        sector_t threshold;
-       unsigned int this_count = rq->nr_sectors;
+       unsigned int this_count = blk_rq_sectors(rq);
        int ret, host_dif;
 
        if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
@@ -413,10 +413,10 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
                                        this_count));
 
        if (!sdp || !scsi_device_online(sdp) ||
-           block + rq->nr_sectors > get_capacity(disk)) {
+           block + blk_rq_sectors(rq) > get_capacity(disk)) {
                SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
-                                               "Finishing %ld sectors\n",
-                                               rq->nr_sectors));
+                                               "Finishing %u sectors\n",
+                                               blk_rq_sectors(rq)));
                SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
                                                "Retry with 0x%p\n", SCpnt));
                goto out;
@@ -463,7 +463,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
         * for this.
         */
        if (sdp->sector_size == 1024) {
-               if ((block & 1) || (rq->nr_sectors & 1)) {
+               if ((block & 1) || (blk_rq_sectors(rq) & 1)) {
                        scmd_printk(KERN_ERR, SCpnt,
                                    "Bad block number requested\n");
                        goto out;
@@ -473,7 +473,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
                }
        }
        if (sdp->sector_size == 2048) {
-               if ((block & 3) || (rq->nr_sectors & 3)) {
+               if ((block & 3) || (blk_rq_sectors(rq) & 3)) {
                        scmd_printk(KERN_ERR, SCpnt,
                                    "Bad block number requested\n");
                        goto out;
@@ -483,7 +483,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
                }
        }
        if (sdp->sector_size == 4096) {
-               if ((block & 7) || (rq->nr_sectors & 7)) {
+               if ((block & 7) || (blk_rq_sectors(rq) & 7)) {
                        scmd_printk(KERN_ERR, SCpnt,
                                    "Bad block number requested\n");
                        goto out;
@@ -512,10 +512,10 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
        }
 
        SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
-                                       "%s %d/%ld 512 byte blocks.\n",
+                                       "%s %d/%u 512 byte blocks.\n",
                                        (rq_data_dir(rq) == WRITE) ?
                                        "writing" : "reading", this_count,
-                                       rq->nr_sectors));
+                                       blk_rq_sectors(rq)));
 
        /* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */
        host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type);
@@ -971,8 +971,8 @@ static struct block_device_operations sd_fops = {
 
 static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
 {
-       u64 start_lba = scmd->request->sector;
-       u64 end_lba = scmd->request->sector + (scsi_bufflen(scmd) / 512);
+       u64 start_lba = blk_rq_pos(scmd->request);
+       u64 end_lba = blk_rq_pos(scmd->request) + (scsi_bufflen(scmd) / 512);
        u64 bad_lba;
        int info_valid;
 
@@ -1510,7 +1510,7 @@ got_data:
                 */
                sector_size = 512;
        }
-       blk_queue_hardsect_size(sdp->request_queue, sector_size);
+       blk_queue_logical_block_size(sdp->request_queue, sector_size);
 
        {
                char cap_str_2[10], cap_str_10[10];
index 184dff492797e960c2a65ae4fce5f81ead4c3654..82f14a9482d0791fdd852a397eb2641e2f09e192 100644 (file)
@@ -507,7 +507,7 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
        sector_sz = scmd->device->sector_size;
        sectors = good_bytes / sector_sz;
 
-       phys = scmd->request->sector & 0xffffffff;
+       phys = blk_rq_pos(scmd->request) & 0xffffffff;
        if (sector_sz == 4096)
                phys >>= 3;
 
index e1716f14cd4710cca0363eab985cdf370d9b9879..8201387b4daa29c374cc850107f8b3d6d21ae0dd 100644 (file)
@@ -289,8 +289,8 @@ sg_open(struct inode *inode, struct file *filp)
        if (list_empty(&sdp->sfds)) {   /* no existing opens on this device */
                sdp->sgdebug = 0;
                q = sdp->device->request_queue;
-               sdp->sg_tablesize = min(q->max_hw_segments,
-                                       q->max_phys_segments);
+               sdp->sg_tablesize = min(queue_max_hw_segments(q),
+                                       queue_max_phys_segments(q));
        }
        if ((sfp = sg_add_sfp(sdp, dev)))
                filp->private_data = sfp;
@@ -909,7 +909,7 @@ sg_ioctl(struct inode *inode, struct file *filp,
                 if (val < 0)
                         return -EINVAL;
                val = min_t(int, val,
-                               sdp->device->request_queue->max_sectors * 512);
+                           queue_max_sectors(sdp->device->request_queue) * 512);
                if (val != sfp->reserve.bufflen) {
                        if (sg_res_in_use(sfp) || sfp->mmap_called)
                                return -EBUSY;
@@ -919,7 +919,7 @@ sg_ioctl(struct inode *inode, struct file *filp,
                return 0;
        case SG_GET_RESERVED_SIZE:
                val = min_t(int, sfp->reserve.bufflen,
-                               sdp->device->request_queue->max_sectors * 512);
+                           queue_max_sectors(sdp->device->request_queue) * 512);
                return put_user(val, ip);
        case SG_SET_COMMAND_Q:
                result = get_user(val, ip);
@@ -1059,12 +1059,13 @@ sg_ioctl(struct inode *inode, struct file *filp,
                        return -ENODEV;
                return scsi_ioctl(sdp->device, cmd_in, p);
        case BLKSECTGET:
-               return put_user(sdp->device->request_queue->max_sectors * 512,
+               return put_user(queue_max_sectors(sdp->device->request_queue) * 512,
                                ip);
        case BLKTRACESETUP:
                return blk_trace_setup(sdp->device->request_queue,
                                       sdp->disk->disk_name,
                                       MKDEV(SCSI_GENERIC_MAJOR, sdp->index),
+                                      NULL,
                                       (char *)arg);
        case BLKTRACESTART:
                return blk_trace_startstop(sdp->device->request_queue, 1);
@@ -1260,7 +1261,7 @@ static void sg_rq_end_io(struct request *rq, int uptodate)
 
        sense = rq->sense;
        result = rq->errors;
-       resid = rq->data_len;
+       resid = rq->resid_len;
 
        SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n",
                sdp->disk->disk_name, srp->header.pack_id, result));
@@ -1377,7 +1378,8 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
        sdp->device = scsidp;
        INIT_LIST_HEAD(&sdp->sfds);
        init_waitqueue_head(&sdp->o_excl_wait);
-       sdp->sg_tablesize = min(q->max_hw_segments, q->max_phys_segments);
+       sdp->sg_tablesize = min(queue_max_hw_segments(q),
+                               queue_max_phys_segments(q));
        sdp->index = k;
        kref_init(&sdp->d_ref);
 
@@ -2055,7 +2057,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
                sg_big_buff = def_reserved_size;
 
        bufflen = min_t(int, sg_big_buff,
-                       sdp->device->request_queue->max_sectors * 512);
+                       queue_max_sectors(sdp->device->request_queue) * 512);
        sg_build_reserve(sfp, bufflen);
        SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   bufflen=%d, k_use_sg=%d\n",
                           sfp->reserve.bufflen, sfp->reserve.k_use_sg));
index 0e1a0f2d2ad55543f39f0f9f56b6bea2645e5990..cd350dfc1216f290554ec0cd5c732e866492644b 100644 (file)
@@ -292,7 +292,8 @@ static int sr_done(struct scsi_cmnd *SCpnt)
                        if (cd->device->sector_size == 2048)
                                error_sector <<= 2;
                        error_sector &= ~(block_sectors - 1);
-                       good_bytes = (error_sector - SCpnt->request->sector) << 9;
+                       good_bytes = (error_sector -
+                                     blk_rq_pos(SCpnt->request)) << 9;
                        if (good_bytes < 0 || good_bytes >= this_count)
                                good_bytes = 0;
                        /*
@@ -349,8 +350,8 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq)
                                cd->disk->disk_name, block));
 
        if (!cd->device || !scsi_device_online(cd->device)) {
-               SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n",
-                                       rq->nr_sectors));
+               SCSI_LOG_HLQUEUE(2, printk("Finishing %u sectors\n",
+                                          blk_rq_sectors(rq)));
                SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
                goto out;
        }
@@ -413,7 +414,7 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq)
        /*
         * request doesn't start on hw block boundary, add scatter pads
         */
-       if (((unsigned int)rq->sector % (s_size >> 9)) ||
+       if (((unsigned int)blk_rq_pos(rq) % (s_size >> 9)) ||
            (scsi_bufflen(SCpnt) % s_size)) {
                scmd_printk(KERN_NOTICE, SCpnt, "unaligned transfer\n");
                goto out;
@@ -422,14 +423,14 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq)
        this_count = (scsi_bufflen(SCpnt) >> 9) / (s_size >> 9);
 
 
-       SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
+       SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%u 512 byte blocks.\n",
                                cd->cdi.name,
                                (rq_data_dir(rq) == WRITE) ?
                                        "writing" : "reading",
-                               this_count, rq->nr_sectors));
+                               this_count, blk_rq_sectors(rq)));
 
        SCpnt->cmnd[1] = 0;
-       block = (unsigned int)rq->sector / (s_size >> 9);
+       block = (unsigned int)blk_rq_pos(rq) / (s_size >> 9);
 
        if (this_count > 0xffff) {
                this_count = 0xffff;
@@ -726,7 +727,7 @@ static void get_sectorsize(struct scsi_cd *cd)
        }
 
        queue = cd->device->request_queue;
-       blk_queue_hardsect_size(queue, sector_size);
+       blk_queue_logical_block_size(queue, sector_size);
 
        return;
 }
index eb24efea8f1450ad9dabdf7a08aa3ada2b0e675d..89bd438e1fe30692e006a0bac18c18fc4c21cd86 100644 (file)
@@ -463,7 +463,7 @@ static void st_scsi_execute_end(struct request *req, int uptodate)
        struct scsi_tape *STp = SRpnt->stp;
 
        STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors;
-       STp->buffer->cmdstat.residual = req->data_len;
+       STp->buffer->cmdstat.residual = req->resid_len;
 
        if (SRpnt->waiting)
                complete(SRpnt->waiting);
@@ -3983,8 +3983,8 @@ static int st_probe(struct device *dev)
                return -ENODEV;
        }
 
-       i = min(SDp->request_queue->max_hw_segments,
-               SDp->request_queue->max_phys_segments);
+       i = min(queue_max_hw_segments(SDp->request_queue),
+               queue_max_phys_segments(SDp->request_queue));
        if (st_max_sg_segs < i)
                i = st_max_sg_segs;
        buffer = new_tape_buffer((SDp->host)->unchecked_isa_dma, i);
index 601e95141cbe13e16570db74c9d826e0e6c864e5..54023d41fd15cdcd69b9391653f21f544927cb01 100644 (file)
@@ -1306,7 +1306,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs
    if (linked_comm && SCpnt->device->queue_depth > 2
                                      && TLDEV(SCpnt->device->type)) {
       HD(j)->cp_stat[i] = READY;
-      flush_dev(SCpnt->device, SCpnt->request->sector, j, FALSE);
+      flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), j, FALSE);
       return 0;
       }
 
@@ -1610,11 +1610,13 @@ static int reorder(unsigned int j, unsigned long cursec,
 
       if (!(cpp->xdir == DTD_IN)) input_only = FALSE;
 
-      if (SCpnt->request->sector < minsec) minsec = SCpnt->request->sector;
-      if (SCpnt->request->sector > maxsec) maxsec = SCpnt->request->sector;
+      if (blk_rq_pos(SCpnt->request) < minsec)
+        minsec = blk_rq_pos(SCpnt->request);
+      if (blk_rq_pos(SCpnt->request) > maxsec)
+        maxsec = blk_rq_pos(SCpnt->request);
 
-      sl[n] = SCpnt->request->sector;
-      ioseek += SCpnt->request->nr_sectors;
+      sl[n] = blk_rq_pos(SCpnt->request);
+      ioseek += blk_rq_sectors(SCpnt->request);
 
       if (!n) continue;
 
@@ -1642,7 +1644,7 @@ static int reorder(unsigned int j, unsigned long cursec,
 
    if (!input_only) for (n = 0; n < n_ready; n++) {
       k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
-      ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->serial_number;
+      ll[n] = blk_rq_sectors(SCpnt->request); pl[n] = SCpnt->serial_number;
 
       if (!n) continue;
 
@@ -1666,12 +1668,12 @@ static int reorder(unsigned int j, unsigned long cursec,
    if (link_statistics && (overlap || !(flushcount % link_statistics)))
       for (n = 0; n < n_ready; n++) {
          k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
-         printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld"\
+         printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %u"\
                 " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
                 (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target,
                 SCpnt->lun, SCpnt->serial_number, k, flushcount, n_ready,
-                SCpnt->request->sector, SCpnt->request->nr_sectors, cursec,
-                YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
+                blk_rq_pos(SCpnt->request), blk_rq_sectors(SCpnt->request),
+               cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
                 YESNO(overlap), cpp->xdir);
          }
 #endif
@@ -1799,7 +1801,7 @@ static irqreturn_t ihdlr(unsigned int j)
 
    if (linked_comm && SCpnt->device->queue_depth > 2
                                      && TLDEV(SCpnt->device->type))
-      flush_dev(SCpnt->device, SCpnt->request->sector, j, TRUE);
+      flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), j, TRUE);
 
    tstatus = status_byte(spp->target_status);
 
index a0127e93ade0a424c6125383150dd342e61710fc..fb867a9f55e94957e1a59ec5cb1f78b85865797e 100644 (file)
@@ -287,6 +287,13 @@ static const struct serial8250_config uart_config[] = {
                .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
                .flags          = UART_CAP_FIFO,
        },
+       [PORT_AR7] = {
+               .name           = "AR7",
+               .fifo_size      = 16,
+               .tx_loadsz      = 16,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
+               .flags          = UART_CAP_FIFO | UART_CAP_AFE,
+       },
 };
 
 #if defined (CONFIG_SERIAL_8250_AU1X00)
index 938bc1b6c3faada842cf6b667db5e4817fe6dc75..e371a9c15341e2598825affdbd2ef1d727dfbde7 100644 (file)
@@ -2776,6 +2776,9 @@ static struct pci_device_id serial_pci_tbl[] = {
        {       PCI_VENDOR_ID_OXSEMI, 0x950a,
                PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                pbn_b0_2_1130000 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950,
+               PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0,
+               pbn_b0_1_921600 },
        {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
                PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                pbn_b0_4_115200 },
index 343e3a35b6a37e0b248ad0195610998b8a3b46e5..641e800ed69333fbafc3b06dd982a0a3ec7f7605 100644 (file)
@@ -833,6 +833,7 @@ config SERIAL_IMX
        bool "IMX serial port support"
        depends on ARM && (ARCH_IMX || ARCH_MXC)
        select SERIAL_CORE
+       select RATIONAL
        help
          If you have a machine based on a Motorola IMX CPU you
          can enable its onboard serial port by enabling this option.
@@ -1433,4 +1434,11 @@ config SPORT_BAUD_RATE
        default 19200 if (SERIAL_SPORT_BAUD_RATE_19200)
        default 9600 if (SERIAL_SPORT_BAUD_RATE_9600)
 
+config SERIAL_TIMBERDALE
+       tristate "Support for timberdale UART"
+       depends on MFD_TIMBERDALE
+       select SERIAL_CORE
+       ---help---
+       Add support for UART controller on timberdale.
+
 endmenu
index d438eb2a73defd29ca9cfab294fa95b20d09fc5f..45a8658f54d5154e1c31c328551ccb73f3da8db7 100644 (file)
@@ -77,3 +77,4 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
 obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
 obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
 obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
+obj-$(CONFIG_SERIAL_TIMBERDALE)        += timbuart.o
index d86123e03391e97623103682271da36f51350ab2..e2f6b1bfac98c726198f35f6bffc153abddc7423 100644 (file)
@@ -330,6 +330,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
                /* Clear TFI bit */
                UART_PUT_LSR(uart, TFI);
 #endif
+               /* Anomaly notes:
+                *  05000215 -  we always clear ETBEI within last UART TX
+                *              interrupt to end a string. It is always set
+                *              when start a new tx.
+                */
                UART_CLEAR_IER(uart, ETBEI);
                return;
        }
@@ -415,6 +420,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
        set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
        set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
        set_dma_x_modify(uart->tx_dma_channel, 1);
+       SSYNC();
        enable_dma(uart->tx_dma_channel);
 
        UART_SET_IER(uart, ETBEI);
@@ -473,27 +479,41 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
 void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
 {
        int x_pos, pos;
-       unsigned long flags;
-
-       spin_lock_irqsave(&uart->port.lock, flags);
 
+       dma_disable_irq(uart->rx_dma_channel);
+       spin_lock_bh(&uart->port.lock);
+
+       /* 2D DMA RX buffer ring is used. Because curr_y_count and
+        * curr_x_count can't be read as an atomic operation,
+        * curr_y_count should be read before curr_x_count. When
+        * curr_x_count is read, curr_y_count may already indicate
+        * next buffer line. But, the position calculated here is
+        * still indicate the old line. The wrong position data may
+        * be smaller than current buffer tail, which cause garbages
+        * are received if it is not prohibit.
+        */
        uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
        x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
        uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
-       if (uart->rx_dma_nrows == DMA_RX_YCOUNT)
+       if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
                uart->rx_dma_nrows = 0;
        x_pos = DMA_RX_XCOUNT - x_pos;
        if (x_pos == DMA_RX_XCOUNT)
                x_pos = 0;
 
        pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;
-       if (pos != uart->rx_dma_buf.tail) {
+       /* Ignore receiving data if new position is in the same line of
+        * current buffer tail and small.
+        */
+       if (pos > uart->rx_dma_buf.tail ||
+               uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
                uart->rx_dma_buf.head = pos;
                bfin_serial_dma_rx_chars(uart);
                uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
        }
 
-       spin_unlock_irqrestore(&uart->port.lock, flags);
+       spin_unlock_bh(&uart->port.lock);
+       dma_enable_irq(uart->rx_dma_channel);
 
        mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
 }
@@ -514,6 +534,11 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
        if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
                disable_dma(uart->tx_dma_channel);
                clear_dma_irqstat(uart->tx_dma_channel);
+               /* Anomaly notes:
+                *  05000215 -  we always clear ETBEI within last UART TX
+                *              interrupt to end a string. It is always set
+                *              when start a new tx.
+                */
                UART_CLEAR_IER(uart, ETBEI);
                xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
                uart->port.icount.tx += uart->tx_count;
@@ -532,11 +557,26 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
 {
        struct bfin_serial_port *uart = dev_id;
        unsigned short irqstat;
+       int x_pos, pos;
 
        spin_lock(&uart->port.lock);
        irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
        clear_dma_irqstat(uart->rx_dma_channel);
-       bfin_serial_dma_rx_chars(uart);
+
+       uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
+       x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
+       uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
+       if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
+               uart->rx_dma_nrows = 0;
+
+       pos = uart->rx_dma_nrows * DMA_RX_XCOUNT;
+       if (pos > uart->rx_dma_buf.tail ||
+               uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
+               uart->rx_dma_buf.head = pos;
+               bfin_serial_dma_rx_chars(uart);
+               uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
+       }
+
        spin_unlock(&uart->port.lock);
 
        return IRQ_HANDLED;
@@ -789,8 +829,16 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
                        __func__);
        }
 
-       if (termios->c_cflag & CSTOPB)
-               lcr |= STB;
+       /* Anomaly notes:
+        *  05000231 -  STOP bit is always set to 1 whatever the user is set.
+        */
+       if (termios->c_cflag & CSTOPB) {
+               if (ANOMALY_05000231)
+                       printk(KERN_WARNING "STOP bits other than 1 is not "
+                               "supported in case of anomaly 05000231.\n");
+               else
+                       lcr |= STB;
+       }
        if (termios->c_cflag & PARENB)
                lcr |= PEN;
        if (!(termios->c_cflag & PARODD))
@@ -940,6 +988,10 @@ static void bfin_serial_reset_irda(struct uart_port *port)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+/* Anomaly notes:
+ *  05000099 -  Because we only use THRE in poll_put and DR in poll_get,
+ *             losing other bits of UART_LSR is not a problem here.
+ */
 static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr)
 {
        struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
@@ -1245,12 +1297,17 @@ static __init void early_serial_write(struct console *con, const char *s,
        }
 }
 
+/*
+ * This should have a .setup or .early_setup in it, but then things get called
+ * without the command line options, and the baud rate gets messed up - so
+ * don't let the common infrastructure play with things. (see calls to setup
+ * & earlysetup in ./kernel/printk.c:register_console()
+ */
 static struct __initdata console bfin_early_serial_console = {
        .name = "early_BFuart",
        .write = early_serial_write,
        .device = uart_console_device,
        .flags = CON_PRINTBUFFER,
-       .setup = bfin_serial_console_setup,
        .index = -1,
        .data  = &bfin_serial_reg,
 };
index 529c0ff7952ceca111e8db153a3794448ca3b5ae..34b4ae0fe76041f4eda4132e1a81a54784652557 100644 (file)
@@ -101,15 +101,16 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
 {
        pr_debug("%s value:%x\n", __func__, value);
        /* Place a Start and Stop bit */
-       __asm__ volatile (
-               "R2 = b#01111111100;\n\t"
-               "R3 = b#10000000001;\n\t"
-               "%0 <<= 2;\n\t"
-               "%0 = %0 & R2;\n\t"
-               "%0 = %0 | R3;\n\t"
-               :"=r"(value)
-               :"0"(value)
-               :"R2", "R3");
+       __asm__ __volatile__ (
+               "R2 = b#01111111100;"
+               "R3 = b#10000000001;"
+               "%0 <<= 2;"
+               "%0 = %0 & R2;"
+               "%0 = %0 | R3;"
+               : "=d"(value)
+               : "d"(value)
+               : "ASTAT", "R2", "R3"
+       );
        pr_debug("%s value:%x\n", __func__, value);
 
        SPORT_PUT_TX(up, value);
@@ -118,27 +119,30 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
 static inline unsigned int rx_one_byte(struct sport_uart_port *up)
 {
        unsigned int value, extract;
+       u32 tmp_mask1, tmp_mask2, tmp_shift, tmp;
 
        value = SPORT_GET_RX32(up);
        pr_debug("%s value:%x\n", __func__, value);
 
        /* Extract 8 bits data */
-       __asm__ volatile (
-               "R5 = 0;\n\t"
-               "P0 = 8;\n\t"
-               "R1 = 0x1801(Z);\n\t"
-               "R3 = 0x0300(Z);\n\t"
-               "R4 = 0;\n\t"
-               "LSETUP(loop_s, loop_e) LC0 = P0;\nloop_s:\t"
-               "R2 = extract(%1, R1.L)(Z);\n\t"
-               "R2 <<= R4;\n\t"
-               "R5 = R5 | R2;\n\t"
-               "R1 = R1 - R3;\nloop_e:\t"
-               "R4 += 1;\n\t"
-               "%0 = R5;\n\t"
-               :"=r"(extract)
-               :"r"(value)
-               :"P0", "R1", "R2","R3","R4", "R5");
+       __asm__ __volatile__ (
+               "%[extr] = 0;"
+               "%[mask1] = 0x1801(Z);"
+               "%[mask2] = 0x0300(Z);"
+               "%[shift] = 0;"
+               "LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];"
+               ".Lloop_s:"
+               "%[tmp] = extract(%[val], %[mask1].L)(Z);"
+               "%[tmp] <<= %[shift];"
+               "%[extr] = %[extr] | %[tmp];"
+               "%[mask1] = %[mask1] - %[mask2];"
+               ".Lloop_e:"
+               "%[shift] += 1;"
+               : [val]"=d"(value), [extr]"=d"(extract), [shift]"=d"(tmp_shift), [tmp]"=d"(tmp),
+                 [mask1]"=d"(tmp_mask1), [mask2]"=d"(tmp_mask2)
+               : "d"(value), [lc]"a"(8)
+               : "ASTAT", "LB0", "LC0", "LT0"
+       );
 
        pr_debug("      extract:%x\n", extract);
        return extract;
@@ -149,7 +153,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate)
        int tclkdiv, tfsdiv, rclkdiv;
 
        /* Set TCR1 and TCR2 */
-       SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK));
+       SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK));
        SPORT_PUT_TCR2(up, 10);
        pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
 
@@ -419,7 +423,7 @@ static void sport_shutdown(struct uart_port *port)
 }
 
 static void sport_set_termios(struct uart_port *port,
-               struct termios *termios, struct termios *old)
+               struct ktermios *termios, struct ktermios *old)
 {
        pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag);
        uart_update_timeout(port, CS8 ,port->uartclk);
index a461b3b2c72dcd63d79e02b1188843a87e092f13..9f2891c2c4a21f93e4cc6289e4b95c286a655455 100644 (file)
@@ -137,7 +137,12 @@ static LIST_HEAD(icom_adapter_head);
 static spinlock_t icom_lock;
 
 #ifdef ICOM_TRACE
-static inline void trace(struct icom_port *, char *, unsigned long) {};
+static inline void trace(struct icom_port *icom_port, char *trace_pt,
+                       unsigned long trace_data)
+{
+       dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n",
+       icom_port->port, trace_pt, trace_data);
+}
 #else
 static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
 #endif
@@ -408,7 +413,7 @@ static void load_code(struct icom_port *icom_port)
        release_firmware(fw);
 
        /* Set Hardware level */
-       if ((icom_port->adapter->version | ADAPTER_V2) == ADAPTER_V2)
+       if (icom_port->adapter->version == ADAPTER_V2)
                writeb(V2_HARDWARE, &(icom_port->dram->misc_flags));
 
        /* Start the processor in Adapter */
@@ -861,7 +866,7 @@ static irqreturn_t icom_interrupt(int irq, void *dev_id)
        /* find icom_port for this interrupt */
        icom_adapter = (struct icom_adapter *) dev_id;
 
-       if ((icom_adapter->version | ADAPTER_V2) == ADAPTER_V2) {
+       if (icom_adapter->version == ADAPTER_V2) {
                int_reg = icom_adapter->base_addr + 0x8024;
 
                adapter_interrupts = readl(int_reg);
@@ -1647,15 +1652,6 @@ static void __exit icom_exit(void)
 module_init(icom_init);
 module_exit(icom_exit);
 
-#ifdef ICOM_TRACE
-static inline void trace(struct icom_port *icom_port, char *trace_pt,
-                 unsigned long trace_data)
-{
-       dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n",
-                icom_port->port, trace_pt, trace_data);
-}
-#endif
-
 MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>");
 MODULE_DESCRIPTION("IBM iSeries Serial IOA driver");
 MODULE_SUPPORTED_DEVICE
index 5f0be40dfdab7292ae65b4c763f4ee4105e36e24..7b5d1de9cfe39c3436d1074bb3b9c77933743507 100644 (file)
@@ -8,6 +8,9 @@
  *  Author: Sascha Hauer <sascha@saschahauer.de>
  *  Copyright (C) 2004 Pengutronix
  *
+ *  Copyright (C) 2009 emlix GmbH
+ *  Author: Fabian Godehardt (added IrDA support for iMX)
+ *
  * 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
@@ -41,6 +44,8 @@
 #include <linux/serial_core.h>
 #include <linux/serial.h>
 #include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/rational.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #define  UCR4_DREN      (1<<0)  /* Recv data ready interrupt enable */
 #define  UFCR_RXTL_SHF   0       /* Receiver trigger level shift */
 #define  UFCR_RFDIV      (7<<7)  /* Reference freq divider mask */
+#define  UFCR_RFDIV_REG(x)     (((x) < 7 ? 6 - (x) : 6) << 7)
 #define  UFCR_TXTL_SHF   10      /* Transmitter trigger level shift */
 #define  USR1_PARITYERR  (1<<15) /* Parity error interrupt flag */
 #define  USR1_RTSS      (1<<14) /* RTS pin status */
@@ -211,10 +217,20 @@ struct imx_port {
        struct timer_list       timer;
        unsigned int            old_status;
        int                     txirq,rxirq,rtsirq;
-       int                     have_rtscts:1;
+       unsigned int            have_rtscts:1;
+       unsigned int            use_irda:1;
+       unsigned int            irda_inv_rx:1;
+       unsigned int            irda_inv_tx:1;
+       unsigned short          trcv_delay; /* transceiver delay */
        struct clk              *clk;
 };
 
+#ifdef CONFIG_IRDA
+#define USE_IRDA(sport)        ((sport)->use_irda)
+#else
+#define USE_IRDA(sport)        (0)
+#endif
+
 /*
  * Handle any change of modem status signal since we were last called.
  */
@@ -268,6 +284,48 @@ static void imx_stop_tx(struct uart_port *port)
        struct imx_port *sport = (struct imx_port *)port;
        unsigned long temp;
 
+       if (USE_IRDA(sport)) {
+               /* half duplex - wait for end of transmission */
+               int n = 256;
+               while ((--n > 0) &&
+                     !(readl(sport->port.membase + USR2) & USR2_TXDC)) {
+                       udelay(5);
+                       barrier();
+               }
+               /*
+                * irda transceiver - wait a bit more to avoid
+                * cutoff, hardware dependent
+                */
+               udelay(sport->trcv_delay);
+
+               /*
+                * half duplex - reactivate receive mode,
+                * flush receive pipe echo crap
+                */
+               if (readl(sport->port.membase + USR2) & USR2_TXDC) {
+                       temp = readl(sport->port.membase + UCR1);
+                       temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN);
+                       writel(temp, sport->port.membase + UCR1);
+
+                       temp = readl(sport->port.membase + UCR4);
+                       temp &= ~(UCR4_TCEN);
+                       writel(temp, sport->port.membase + UCR4);
+
+                       while (readl(sport->port.membase + URXD0) &
+                              URXD_CHARRDY)
+                               barrier();
+
+                       temp = readl(sport->port.membase + UCR1);
+                       temp |= UCR1_RRDYEN;
+                       writel(temp, sport->port.membase + UCR1);
+
+                       temp = readl(sport->port.membase + UCR4);
+                       temp |= UCR4_DREN;
+                       writel(temp, sport->port.membase + UCR4);
+               }
+               return;
+       }
+
        temp = readl(sport->port.membase + UCR1);
        writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
 }
@@ -302,13 +360,15 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
                /* send xmit->buf[xmit->tail]
                 * out the port here */
                writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
-               xmit->tail = (xmit->tail + 1) &
-                        (UART_XMIT_SIZE - 1);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
                sport->port.icount.tx++;
                if (uart_circ_empty(xmit))
                        break;
        }
 
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&sport->port);
+
        if (uart_circ_empty(xmit))
                imx_stop_tx(&sport->port);
 }
@@ -321,9 +381,30 @@ static void imx_start_tx(struct uart_port *port)
        struct imx_port *sport = (struct imx_port *)port;
        unsigned long temp;
 
+       if (USE_IRDA(sport)) {
+               /* half duplex in IrDA mode; have to disable receive mode */
+               temp = readl(sport->port.membase + UCR4);
+               temp &= ~(UCR4_DREN);
+               writel(temp, sport->port.membase + UCR4);
+
+               temp = readl(sport->port.membase + UCR1);
+               temp &= ~(UCR1_RRDYEN);
+               writel(temp, sport->port.membase + UCR1);
+       }
+
        temp = readl(sport->port.membase + UCR1);
        writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
 
+       if (USE_IRDA(sport)) {
+               temp = readl(sport->port.membase + UCR1);
+               temp |= UCR1_TRDYEN;
+               writel(temp, sport->port.membase + UCR1);
+
+               temp = readl(sport->port.membase + UCR4);
+               temp |= UCR4_TCEN;
+               writel(temp, sport->port.membase + UCR4);
+       }
+
        if (readl(sport->port.membase + UTS) & UTS_TXEMPTY)
                imx_transmit_buffer(sport);
 }
@@ -395,8 +476,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
                                continue;
                }
 
-               if (uart_handle_sysrq_char
-                           (&sport->port, (unsigned char)rx))
+               if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
                        continue;
 
                if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
@@ -471,26 +551,26 @@ static unsigned int imx_tx_empty(struct uart_port *port)
  */
 static unsigned int imx_get_mctrl(struct uart_port *port)
 {
-        struct imx_port *sport = (struct imx_port *)port;
-        unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
 
-        if (readl(sport->port.membase + USR1) & USR1_RTSS)
-                tmp |= TIOCM_CTS;
+       if (readl(sport->port.membase + USR1) & USR1_RTSS)
+               tmp |= TIOCM_CTS;
 
-        if (readl(sport->port.membase + UCR2) & UCR2_CTS)
-                tmp |= TIOCM_RTS;
+       if (readl(sport->port.membase + UCR2) & UCR2_CTS)
+               tmp |= TIOCM_RTS;
 
-        return tmp;
+       return tmp;
 }
 
 static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-        struct imx_port *sport = (struct imx_port *)port;
+       struct imx_port *sport = (struct imx_port *)port;
        unsigned long temp;
 
        temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
 
-        if (mctrl & TIOCM_RTS)
+       if (mctrl & TIOCM_RTS)
                temp |= UCR2_CTS;
 
        writel(temp, sport->port.membase + UCR2);
@@ -534,12 +614,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
        if(!ufcr_rfdiv)
                ufcr_rfdiv = 1;
 
-       if(ufcr_rfdiv >= 7)
-               ufcr_rfdiv = 6;
-       else
-               ufcr_rfdiv = 6 - ufcr_rfdiv;
-
-       val |= UFCR_RFDIV & (ufcr_rfdiv << 7);
+       val |= UFCR_RFDIV_REG(ufcr_rfdiv);
 
        writel(val, sport->port.membase + UFCR);
 
@@ -558,8 +633,24 @@ static int imx_startup(struct uart_port *port)
         * requesting IRQs
         */
        temp = readl(sport->port.membase + UCR4);
+
+       if (USE_IRDA(sport))
+               temp |= UCR4_IRSC;
+
        writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
 
+       if (USE_IRDA(sport)) {
+               /* reset fifo's and state machines */
+               int i = 100;
+               temp = readl(sport->port.membase + UCR2);
+               temp &= ~UCR2_SRST;
+               writel(temp, sport->port.membase + UCR2);
+               while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) &&
+                   (--i > 0)) {
+                       udelay(1);
+               }
+       }
+
        /*
         * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
         * chips only have one interrupt.
@@ -575,12 +666,16 @@ static int imx_startup(struct uart_port *port)
                if (retval)
                        goto error_out2;
 
-               retval = request_irq(sport->rtsirq, imx_rtsint,
-                            (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
-                              IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-                               DRIVER_NAME, sport);
-               if (retval)
-                       goto error_out3;
+               /* do not use RTS IRQ on IrDA */
+               if (!USE_IRDA(sport)) {
+                       retval = request_irq(sport->rtsirq, imx_rtsint,
+                                    (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
+                                      IRQF_TRIGGER_FALLING |
+                                      IRQF_TRIGGER_RISING,
+                                       DRIVER_NAME, sport);
+                       if (retval)
+                               goto error_out3;
+               }
        } else {
                retval = request_irq(sport->port.irq, imx_int, 0,
                                DRIVER_NAME, sport);
@@ -597,18 +692,49 @@ static int imx_startup(struct uart_port *port)
 
        temp = readl(sport->port.membase + UCR1);
        temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
+
+       if (USE_IRDA(sport)) {
+               temp |= UCR1_IREN;
+               temp &= ~(UCR1_RTSDEN);
+       }
+
        writel(temp, sport->port.membase + UCR1);
 
        temp = readl(sport->port.membase + UCR2);
        temp |= (UCR2_RXEN | UCR2_TXEN);
        writel(temp, sport->port.membase + UCR2);
 
+       if (USE_IRDA(sport)) {
+               /* clear RX-FIFO */
+               int i = 64;
+               while ((--i > 0) &&
+                       (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) {
+                       barrier();
+               }
+       }
+
 #if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3
        temp = readl(sport->port.membase + UCR3);
        temp |= UCR3_RXDMUXSEL;
        writel(temp, sport->port.membase + UCR3);
 #endif
 
+       if (USE_IRDA(sport)) {
+               temp = readl(sport->port.membase + UCR4);
+               if (sport->irda_inv_rx)
+                       temp |= UCR4_INVR;
+               else
+                       temp &= ~(UCR4_INVR);
+               writel(temp | UCR4_DREN, sport->port.membase + UCR4);
+
+               temp = readl(sport->port.membase + UCR3);
+               if (sport->irda_inv_tx)
+                       temp |= UCR3_INVT;
+               else
+                       temp &= ~(UCR3_INVT);
+               writel(temp, sport->port.membase + UCR3);
+       }
+
        /*
         * Enable modem status interrupts
         */
@@ -616,6 +742,16 @@ static int imx_startup(struct uart_port *port)
        imx_enable_ms(&sport->port);
        spin_unlock_irqrestore(&sport->port.lock,flags);
 
+       if (USE_IRDA(sport)) {
+               struct imxuart_platform_data *pdata;
+               pdata = sport->port.dev->platform_data;
+               sport->irda_inv_rx = pdata->irda_inv_rx;
+               sport->irda_inv_tx = pdata->irda_inv_tx;
+               sport->trcv_delay = pdata->transceiver_delay;
+               if (pdata->irda_enable)
+                       pdata->irda_enable(1);
+       }
+
        return 0;
 
 error_out3:
@@ -633,6 +769,17 @@ static void imx_shutdown(struct uart_port *port)
        struct imx_port *sport = (struct imx_port *)port;
        unsigned long temp;
 
+       temp = readl(sport->port.membase + UCR2);
+       temp &= ~(UCR2_TXEN);
+       writel(temp, sport->port.membase + UCR2);
+
+       if (USE_IRDA(sport)) {
+               struct imxuart_platform_data *pdata;
+               pdata = sport->port.dev->platform_data;
+               if (pdata->irda_enable)
+                       pdata->irda_enable(0);
+       }
+
        /*
         * Stop our timer.
         */
@@ -642,7 +789,8 @@ static void imx_shutdown(struct uart_port *port)
         * Free the interrupts
         */
        if (sport->txirq > 0) {
-               free_irq(sport->rtsirq, sport);
+               if (!USE_IRDA(sport))
+                       free_irq(sport->rtsirq, sport);
                free_irq(sport->txirq, sport);
                free_irq(sport->rxirq, sport);
        } else
@@ -654,6 +802,9 @@ static void imx_shutdown(struct uart_port *port)
 
        temp = readl(sport->port.membase + UCR1);
        temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
+       if (USE_IRDA(sport))
+               temp &= ~(UCR1_IREN);
+
        writel(temp, sport->port.membase + UCR1);
 }
 
@@ -665,7 +816,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
        unsigned long flags;
        unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
        unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
-       unsigned int div, num, denom, ufcr;
+       unsigned int div, ufcr;
+       unsigned long num, denom;
+       uint64_t tdiv64;
 
        /*
         * If we don't support modem control lines, don't allow
@@ -761,38 +914,39 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
                        sport->port.membase + UCR2);
        old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
 
-       div = sport->port.uartclk / (baud * 16);
-       if (div > 7)
-               div = 7;
-       if (!div)
+       if (USE_IRDA(sport)) {
+               /*
+                * use maximum available submodule frequency to
+                * avoid missing short pulses due to low sampling rate
+                */
                div = 1;
-
-       num = baud;
-       denom = port->uartclk / div / 16;
-
-       /* shift num and denom right until they fit into 16 bits */
-       while (num > 0x10000 || denom > 0x10000) {
-               num >>= 1;
-               denom >>= 1;
+       } else {
+               div = sport->port.uartclk / (baud * 16);
+               if (div > 7)
+                       div = 7;
+               if (!div)
+                       div = 1;
        }
-       if (num > 0)
-               num -= 1;
-       if (denom > 0)
-               denom -= 1;
 
-       writel(num, sport->port.membase + UBIR);
-       writel(denom, sport->port.membase + UBMR);
+       rational_best_approximation(16 * div * baud, sport->port.uartclk,
+               1 << 16, 1 << 16, &num, &denom);
 
-       if (div == 7)
-               div = 6; /* 6 in RFDIV means divide by 7 */
-       else
-               div = 6 - div;
+       tdiv64 = sport->port.uartclk;
+       tdiv64 *= num;
+       do_div(tdiv64, denom * 16 * div);
+       tty_encode_baud_rate(sport->port.info->port.tty,
+               (speed_t)tdiv64, (speed_t)tdiv64);
+
+       num -= 1;
+       denom -= 1;
 
        ufcr = readl(sport->port.membase + UFCR);
-       ufcr = (ufcr & (~UFCR_RFDIV)) |
-           (div << 7);
+       ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
        writel(ufcr, sport->port.membase + UFCR);
 
+       writel(num, sport->port.membase + UBIR);
+       writel(denom, sport->port.membase + UBMR);
+
 #ifdef ONEMS
        writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS);
 #endif
@@ -1072,22 +1226,22 @@ static struct uart_driver imx_reg = {
 
 static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
 {
-        struct imx_port *sport = platform_get_drvdata(dev);
+       struct imx_port *sport = platform_get_drvdata(dev);
 
-        if (sport)
-                uart_suspend_port(&imx_reg, &sport->port);
+       if (sport)
+               uart_suspend_port(&imx_reg, &sport->port);
 
-        return 0;
+       return 0;
 }
 
 static int serial_imx_resume(struct platform_device *dev)
 {
-        struct imx_port *sport = platform_get_drvdata(dev);
+       struct imx_port *sport = platform_get_drvdata(dev);
 
-        if (sport)
-                uart_resume_port(&imx_reg, &sport->port);
+       if (sport)
+               uart_resume_port(&imx_reg, &sport->port);
 
-        return 0;
+       return 0;
 }
 
 static int serial_imx_probe(struct platform_device *pdev)
@@ -1143,19 +1297,29 @@ static int serial_imx_probe(struct platform_device *pdev)
        imx_ports[pdev->id] = sport;
 
        pdata = pdev->dev.platform_data;
-       if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
+       if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
                sport->have_rtscts = 1;
 
+#ifdef CONFIG_IRDA
+       if (pdata && (pdata->flags & IMXUART_IRDA))
+               sport->use_irda = 1;
+#endif
+
        if (pdata->init) {
                ret = pdata->init(pdev);
                if (ret)
                        goto clkput;
        }
 
-       uart_add_one_port(&imx_reg, &sport->port);
+       ret = uart_add_one_port(&imx_reg, &sport->port);
+       if (ret)
+               goto deinit;
        platform_set_drvdata(pdev, &sport->port);
 
        return 0;
+deinit:
+       if (pdata->exit)
+               pdata->exit(pdev);
 clkput:
        clk_put(sport->clk);
        clk_disable(sport->clk);
@@ -1193,13 +1357,13 @@ static int serial_imx_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver serial_imx_driver = {
-        .probe          = serial_imx_probe,
-        .remove         = serial_imx_remove,
+       .probe          = serial_imx_probe,
+       .remove         = serial_imx_remove,
 
        .suspend        = serial_imx_suspend,
        .resume         = serial_imx_resume,
        .driver         = {
-               .name   = "imx-uart",
+               .name   = "imx-uart",
                .owner  = THIS_MODULE,
        },
 };
index c0a3e2734e240c02dd6e5a0b4da8a2f66800df86..4e5f3bde0461ca4c8eb4638bcc11643466c697ab 100644 (file)
@@ -61,6 +61,7 @@ enum {
        if ((DBG_##nlevel & jsm_debug))                 \
        dev_printk(KERN_##klevel, pdev->dev, fmt, ## args)
 
+#define        MAXLINES        256
 #define MAXPORTS       8
 #define MAX_STOPS_SENT 5
 
index 31496dc0a0d17d65206cb14ba280a6a5ffe29229..107ce2e187b8fc1c1773530a74b0779fdce283de 100644 (file)
@@ -33,6 +33,8 @@
 
 #include "jsm.h"
 
+static DECLARE_BITMAP(linemap, MAXLINES);
+
 static void jsm_carrier(struct jsm_channel *ch);
 
 static inline int jsm_get_mstat(struct jsm_channel *ch)
@@ -433,6 +435,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd)
 int __devinit jsm_uart_port_init(struct jsm_board *brd)
 {
        int i;
+       unsigned int line;
        struct jsm_channel *ch;
 
        if (!brd)
@@ -459,9 +462,15 @@ int __devinit jsm_uart_port_init(struct jsm_board *brd)
                brd->channels[i]->uart_port.membase = brd->re_map_membase;
                brd->channels[i]->uart_port.fifosize = 16;
                brd->channels[i]->uart_port.ops = &jsm_ops;
-               brd->channels[i]->uart_port.line = brd->channels[i]->ch_portnum + brd->boardnum * 2;
+               line = find_first_zero_bit(linemap, MAXLINES);
+               if (line >= MAXLINES) {
+                       printk(KERN_INFO "jsm: linemap is full, added device failed\n");
+                       continue;
+               } else
+                       set_bit((int)line, linemap);
+               brd->channels[i]->uart_port.line = line;
                if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port))
-                       printk(KERN_INFO "Added device failed\n");
+                       printk(KERN_INFO "jsm: add device failed\n");
                else
                        printk(KERN_INFO "Added device \n");
        }
@@ -494,6 +503,7 @@ int jsm_remove_uart_port(struct jsm_board *brd)
 
                ch = brd->channels[i];
 
+               clear_bit((int)(ch->uart_port.line), linemap);
                uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
        }
 
index dbf5357a77b30e1678e268a485ae51e98c3eb7ce..a4cf1079b3129e4892fb711b5f95276055552458 100644 (file)
 #include <linux/clk.h>
 #include <linux/ctype.h>
 #include <linux/err.h>
+#include <linux/list.h>
 
 #ifdef CONFIG_SUPERH
 #include <asm/clock.h>
 #include <asm/sh_bios.h>
 #endif
 
+#ifdef CONFIG_H8300
+#include <asm/gpio.h>
+#endif
+
 #include "sh-sci.h"
 
 struct sci_port {
@@ -75,14 +80,22 @@ struct sci_port {
        int                     break_flag;
 
 #ifdef CONFIG_HAVE_CLK
-       /* Port clock */
-       struct clk              *clk;
+       /* Interface clock */
+       struct clk              *iclk;
+       /* Data clock */
+       struct clk              *dclk;
 #endif
+       struct list_head        node;
 };
 
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
-static struct sci_port *serial_console_port;
+struct sh_sci_priv {
+       spinlock_t lock;
+       struct list_head ports;
+
+#ifdef CONFIG_HAVE_CLK
+       struct notifier_block clk_nb;
 #endif
+};
 
 /* Function prototypes */
 static void sci_stop_tx(struct uart_port *port);
@@ -138,9 +151,8 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
                status = sci_in(port, SCxSR);
        } while (!(status & SCxSR_TDxE(port)));
 
-       sci_in(port, SCxSR);            /* Dummy read */
-       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
        sci_out(port, SCxTDR, c);
+       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
 }
 #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
 
@@ -159,12 +171,12 @@ static void h8300_sci_config(struct uart_port *port, unsigned int ctrl)
                *mstpcrl &= ~mask;
 }
 
-static inline void h8300_sci_enable(struct uart_port *port)
+static void h8300_sci_enable(struct uart_port *port)
 {
        h8300_sci_config(port, sci_enable);
 }
 
-static inline void h8300_sci_disable(struct uart_port *port)
+static void h8300_sci_disable(struct uart_port *port)
 {
        h8300_sci_config(port, sci_disable);
 }
@@ -611,7 +623,7 @@ static inline int sci_handle_breaks(struct uart_port *port)
        int copied = 0;
        unsigned short status = sci_in(port, SCxSR);
        struct tty_struct *tty = port->info->port.tty;
-       struct sci_port *s = &sci_ports[port->line];
+       struct sci_port *s = to_sci_port(port);
 
        if (uart_handle_break(port))
                return 0;
@@ -726,19 +738,43 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
 static int sci_notifier(struct notifier_block *self,
                        unsigned long phase, void *p)
 {
-       int i;
+       struct sh_sci_priv *priv = container_of(self,
+                                               struct sh_sci_priv, clk_nb);
+       struct sci_port *sci_port;
+       unsigned long flags;
 
        if ((phase == CPUFREQ_POSTCHANGE) ||
-           (phase == CPUFREQ_RESUMECHANGE))
-               for (i = 0; i < SCI_NPORTS; i++) {
-                       struct sci_port *s = &sci_ports[i];
-                       s->port.uartclk = clk_get_rate(s->clk);
-               }
+           (phase == CPUFREQ_RESUMECHANGE)) {
+               spin_lock_irqsave(&priv->lock, flags);
+               list_for_each_entry(sci_port, &priv->ports, node)
+                       sci_port->port.uartclk = clk_get_rate(sci_port->dclk);
+
+               spin_unlock_irqrestore(&priv->lock, flags);
+       }
 
        return NOTIFY_OK;
 }
 
-static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 };
+static void sci_clk_enable(struct uart_port *port)
+{
+       struct sci_port *sci_port = to_sci_port(port);
+
+       clk_enable(sci_port->dclk);
+       sci_port->port.uartclk = clk_get_rate(sci_port->dclk);
+
+       if (sci_port->iclk)
+               clk_enable(sci_port->iclk);
+}
+
+static void sci_clk_disable(struct uart_port *port)
+{
+       struct sci_port *sci_port = to_sci_port(port);
+
+       if (sci_port->iclk)
+               clk_disable(sci_port->iclk);
+
+       clk_disable(sci_port->dclk);
+}
 #endif
 
 static int sci_request_irq(struct sci_port *port)
@@ -865,15 +901,11 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
 
 static int sci_startup(struct uart_port *port)
 {
-       struct sci_port *s = &sci_ports[port->line];
+       struct sci_port *s = to_sci_port(port);
 
        if (s->enable)
                s->enable(port);
 
-#ifdef CONFIG_HAVE_CLK
-       s->clk = clk_get(NULL, "module_clk");
-#endif
-
        sci_request_irq(s);
        sci_start_tx(port);
        sci_start_rx(port, 1);
@@ -883,7 +915,7 @@ static int sci_startup(struct uart_port *port)
 
 static void sci_shutdown(struct uart_port *port)
 {
-       struct sci_port *s = &sci_ports[port->line];
+       struct sci_port *s = to_sci_port(port);
 
        sci_stop_rx(port);
        sci_stop_tx(port);
@@ -891,11 +923,6 @@ static void sci_shutdown(struct uart_port *port)
 
        if (s->disable)
                s->disable(port);
-
-#ifdef CONFIG_HAVE_CLK
-       clk_put(s->clk);
-       s->clk = NULL;
-#endif
 }
 
 static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
@@ -980,25 +1007,31 @@ static int sci_request_port(struct uart_port *port)
 
 static void sci_config_port(struct uart_port *port, int flags)
 {
-       struct sci_port *s = &sci_ports[port->line];
+       struct sci_port *s = to_sci_port(port);
 
        port->type = s->type;
 
-       if (port->flags & UPF_IOREMAP && !port->membase) {
-#if defined(CONFIG_SUPERH64)
-               port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF");
-               port->membase = (void __iomem *)port->mapbase;
-#else
+       if (port->membase)
+               return;
+
+       if (port->flags & UPF_IOREMAP) {
                port->membase = ioremap_nocache(port->mapbase, 0x40);
-#endif
 
-               dev_err(port->dev, "can't remap port#%d\n", port->line);
+               if (IS_ERR(port->membase))
+                       dev_err(port->dev, "can't remap port#%d\n", port->line);
+       } else {
+               /*
+                * For the simple (and majority of) cases where we don't
+                * need to do any remapping, just cast the cookie
+                * directly.
+                */
+               port->membase = (void __iomem *)port->mapbase;
        }
 }
 
 static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
 {
-       struct sci_port *s = &sci_ports[port->line];
+       struct sci_port *s = to_sci_port(port);
 
        if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs)
                return -EINVAL;
@@ -1032,63 +1065,60 @@ static struct uart_ops sci_uart_ops = {
 #endif
 };
 
-static void __init sci_init_ports(void)
+static void __devinit sci_init_single(struct platform_device *dev,
+                                     struct sci_port *sci_port,
+                                     unsigned int index,
+                                     struct plat_sci_port *p)
 {
-       static int first = 1;
-       int i;
-
-       if (!first)
-               return;
-
-       first = 0;
-
-       for (i = 0; i < SCI_NPORTS; i++) {
-               sci_ports[i].port.ops           = &sci_uart_ops;
-               sci_ports[i].port.iotype        = UPIO_MEM;
-               sci_ports[i].port.line          = i;
-               sci_ports[i].port.fifosize      = 1;
+       sci_port->port.ops      = &sci_uart_ops;
+       sci_port->port.iotype   = UPIO_MEM;
+       sci_port->port.line     = index;
+       sci_port->port.fifosize = 1;
 
 #if defined(__H8300H__) || defined(__H8300S__)
 #ifdef __H8300S__
-               sci_ports[i].enable     = h8300_sci_enable;
-               sci_ports[i].disable    = h8300_sci_disable;
+       sci_port->enable        = h8300_sci_enable;
+       sci_port->disable       = h8300_sci_disable;
 #endif
-               sci_ports[i].port.uartclk = CONFIG_CPU_CLOCK;
+       sci_port->port.uartclk  = CONFIG_CPU_CLOCK;
 #elif defined(CONFIG_HAVE_CLK)
-               /*
-                * XXX: We should use a proper SCI/SCIF clock
-                */
-               {
-                       struct clk *clk = clk_get(NULL, "module_clk");
-                       sci_ports[i].port.uartclk = clk_get_rate(clk);
-                       clk_put(clk);
-               }
+       sci_port->iclk          = p->clk ? clk_get(&dev->dev, p->clk) : NULL;
+       sci_port->dclk          = clk_get(&dev->dev, "peripheral_clk");
+       sci_port->enable        = sci_clk_enable;
+       sci_port->disable       = sci_clk_disable;
 #else
 #error "Need a valid uartclk"
 #endif
 
-               sci_ports[i].break_timer.data = (unsigned long)&sci_ports[i];
-               sci_ports[i].break_timer.function = sci_break_timer;
+       sci_port->break_timer.data = (unsigned long)sci_port;
+       sci_port->break_timer.function = sci_break_timer;
+       init_timer(&sci_port->break_timer);
 
-               init_timer(&sci_ports[i].break_timer);
-       }
-}
-
-int __init early_sci_setup(struct uart_port *port)
-{
-       if (unlikely(port->line > SCI_NPORTS))
-               return -ENODEV;
+       sci_port->port.mapbase  = p->mapbase;
+       sci_port->port.membase  = p->membase;
 
-       sci_init_ports();
+       sci_port->port.irq      = p->irqs[SCIx_TXI_IRQ];
+       sci_port->port.flags    = p->flags;
+       sci_port->port.dev      = &dev->dev;
+       sci_port->type          = sci_port->port.type = p->type;
 
-       sci_ports[port->line].port.membase      = port->membase;
-       sci_ports[port->line].port.mapbase      = port->mapbase;
-       sci_ports[port->line].port.type         = port->type;
+       memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs));
 
-       return 0;
 }
 
 #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+static struct tty_driver *serial_console_device(struct console *co, int *index)
+{
+       struct uart_driver *p = &sci_uart_driver;
+       *index = co->index;
+       return p->tty_driver;
+}
+
+static void serial_console_putchar(struct uart_port *port, int ch)
+{
+       sci_poll_put_char(port, ch);
+}
+
 /*
  *     Print a string to the serial port trying not to disturb
  *     any possible real use of the port...
@@ -1096,25 +1126,27 @@ int __init early_sci_setup(struct uart_port *port)
 static void serial_console_write(struct console *co, const char *s,
                                 unsigned count)
 {
-       struct uart_port *port = &serial_console_port->port;
+       struct uart_port *port = co->data;
+       struct sci_port *sci_port = to_sci_port(port);
        unsigned short bits;
-       int i;
 
-       for (i = 0; i < count; i++) {
-               if (*s == 10)
-                       sci_poll_put_char(port, '\r');
+       if (sci_port->enable)
+               sci_port->enable(port);
 
-               sci_poll_put_char(port, *s++);
-       }
+       uart_console_write(port, s, count, serial_console_putchar);
 
        /* wait until fifo is empty and last bit has been transmitted */
        bits = SCxSR_TDxE(port) | SCxSR_TEND(port);
        while ((sci_in(port, SCxSR) & bits) != bits)
                cpu_relax();
+
+       if (sci_port->disable);
+               sci_port->disable(port);
 }
 
 static int __init serial_console_setup(struct console *co, char *options)
 {
+       struct sci_port *sci_port;
        struct uart_port *port;
        int baud = 115200;
        int bits = 8;
@@ -1130,8 +1162,9 @@ static int __init serial_console_setup(struct console *co, char *options)
        if (co->index >= SCI_NPORTS)
                co->index = 0;
 
-       serial_console_port = &sci_ports[co->index];
-       port = &serial_console_port->port;
+       sci_port = &sci_ports[co->index];
+       port = &sci_port->port;
+       co->data = port;
 
        /*
         * Also need to check port->type, we don't actually have any
@@ -1141,21 +1174,11 @@ static int __init serial_console_setup(struct console *co, char *options)
         */
        if (!port->type)
                return -ENODEV;
-       if (!port->membase || !port->mapbase)
-               return -ENODEV;
-
-       port->type = serial_console_port->type;
-
-#ifdef CONFIG_HAVE_CLK
-       if (!serial_console_port->clk)
-               serial_console_port->clk = clk_get(NULL, "module_clk");
-#endif
 
-       if (port->flags & UPF_IOREMAP)
-               sci_config_port(port, 0);
+       sci_config_port(port, 0);
 
-       if (serial_console_port->enable)
-               serial_console_port->enable(port);
+       if (sci_port->enable)
+               sci_port->enable(port);
 
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -1166,22 +1189,21 @@ static int __init serial_console_setup(struct console *co, char *options)
        if (ret == 0)
                sci_stop_rx(port);
 #endif
+       /* TODO: disable clock */
        return ret;
 }
 
 static struct console serial_console = {
        .name           = "ttySC",
-       .device         = uart_console_device,
+       .device         = serial_console_device,
        .write          = serial_console_write,
        .setup          = serial_console_setup,
        .flags          = CON_PRINTBUFFER,
        .index          = -1,
-       .data           = &sci_uart_driver,
 };
 
 static int __init sci_console_init(void)
 {
-       sci_init_ports();
        register_console(&serial_console);
        return 0;
 }
@@ -1207,6 +1229,61 @@ static struct uart_driver sci_uart_driver = {
        .cons           = SCI_CONSOLE,
 };
 
+
+static int sci_remove(struct platform_device *dev)
+{
+       struct sh_sci_priv *priv = platform_get_drvdata(dev);
+       struct sci_port *p;
+       unsigned long flags;
+
+#ifdef CONFIG_HAVE_CLK
+       cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+
+       spin_lock_irqsave(&priv->lock, flags);
+       list_for_each_entry(p, &priv->ports, node)
+               uart_remove_one_port(&sci_uart_driver, &p->port);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       kfree(priv);
+       return 0;
+}
+
+static int __devinit sci_probe_single(struct platform_device *dev,
+                                     unsigned int index,
+                                     struct plat_sci_port *p,
+                                     struct sci_port *sciport)
+{
+       struct sh_sci_priv *priv = platform_get_drvdata(dev);
+       unsigned long flags;
+       int ret;
+
+       /* Sanity check */
+       if (unlikely(index >= SCI_NPORTS)) {
+               dev_notice(&dev->dev, "Attempting to register port "
+                          "%d when only %d are available.\n",
+                          index+1, SCI_NPORTS);
+               dev_notice(&dev->dev, "Consider bumping "
+                          "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
+               return 0;
+       }
+
+       sci_init_single(dev, sciport, index, p);
+
+       ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
+       if (ret)
+               return ret;
+
+       INIT_LIST_HEAD(&sciport->node);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       list_add(&sciport->node, &priv->ports);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
 /*
  * Register a set of serial devices attached to a platform device.  The
  * list is terminated with a zero flags entry, which means we expect
@@ -1216,57 +1293,34 @@ static struct uart_driver sci_uart_driver = {
 static int __devinit sci_probe(struct platform_device *dev)
 {
        struct plat_sci_port *p = dev->dev.platform_data;
+       struct sh_sci_priv *priv;
        int i, ret = -EINVAL;
 
-       for (i = 0; p && p->flags != 0; p++, i++) {
-               struct sci_port *sciport = &sci_ports[i];
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
 
-               /* Sanity check */
-               if (unlikely(i == SCI_NPORTS)) {
-                       dev_notice(&dev->dev, "Attempting to register port "
-                                  "%d when only %d are available.\n",
-                                  i+1, SCI_NPORTS);
-                       dev_notice(&dev->dev, "Consider bumping "
-                                  "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
-                       break;
-               }
+       INIT_LIST_HEAD(&priv->ports);
+       spin_lock_init(&priv->lock);
+       platform_set_drvdata(dev, priv);
 
-               sciport->port.mapbase   = p->mapbase;
+#ifdef CONFIG_HAVE_CLK
+       priv->clk_nb.notifier_call = sci_notifier;
+       cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
+#endif
 
-               if (p->mapbase && !p->membase) {
-                       if (p->flags & UPF_IOREMAP) {
-                               p->membase = ioremap_nocache(p->mapbase, 0x40);
-                               if (IS_ERR(p->membase)) {
-                                       ret = PTR_ERR(p->membase);
-                                       goto err_unreg;
-                               }
-                       } else {
-                               /*
-                                * For the simple (and majority of) cases
-                                * where we don't need to do any remapping,
-                                * just cast the cookie directly.
-                                */
-                               p->membase = (void __iomem *)p->mapbase;
-                       }
+       if (dev->id != -1) {
+               ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]);
+               if (ret)
+                       goto err_unreg;
+       } else {
+               for (i = 0; p && p->flags != 0; p++, i++) {
+                       ret = sci_probe_single(dev, i, p, &sci_ports[i]);
+                       if (ret)
+                               goto err_unreg;
                }
-
-               sciport->port.membase   = p->membase;
-
-               sciport->port.irq       = p->irqs[SCIx_TXI_IRQ];
-               sciport->port.flags     = p->flags;
-               sciport->port.dev       = &dev->dev;
-
-               sciport->type           = sciport->port.type = p->type;
-
-               memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs));
-
-               uart_add_one_port(&sci_uart_driver, &sciport->port);
        }
 
-#ifdef CONFIG_HAVE_CLK
-       cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
-#endif
-
 #ifdef CONFIG_SH_STANDARD_BIOS
        sh_bios_gdb_detach();
 #endif
@@ -1274,50 +1328,36 @@ static int __devinit sci_probe(struct platform_device *dev)
        return 0;
 
 err_unreg:
-       for (i = i - 1; i >= 0; i--)
-               uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port);
-
+       sci_remove(dev);
        return ret;
 }
 
-static int __devexit sci_remove(struct platform_device *dev)
-{
-       int i;
-
-#ifdef CONFIG_HAVE_CLK
-       cpufreq_unregister_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
-#endif
-
-       for (i = 0; i < SCI_NPORTS; i++)
-               uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port);
-
-       return 0;
-}
-
 static int sci_suspend(struct platform_device *dev, pm_message_t state)
 {
-       int i;
+       struct sh_sci_priv *priv = platform_get_drvdata(dev);
+       struct sci_port *p;
+       unsigned long flags;
 
-       for (i = 0; i < SCI_NPORTS; i++) {
-               struct sci_port *p = &sci_ports[i];
+       spin_lock_irqsave(&priv->lock, flags);
+       list_for_each_entry(p, &priv->ports, node)
+               uart_suspend_port(&sci_uart_driver, &p->port);
 
-               if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev)
-                       uart_suspend_port(&sci_uart_driver, &p->port);
-       }
+       spin_unlock_irqrestore(&priv->lock, flags);
 
        return 0;
 }
 
 static int sci_resume(struct platform_device *dev)
 {
-       int i;
+       struct sh_sci_priv *priv = platform_get_drvdata(dev);
+       struct sci_port *p;
+       unsigned long flags;
 
-       for (i = 0; i < SCI_NPORTS; i++) {
-               struct sci_port *p = &sci_ports[i];
+       spin_lock_irqsave(&priv->lock, flags);
+       list_for_each_entry(p, &priv->ports, node)
+               uart_resume_port(&sci_uart_driver, &p->port);
 
-               if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev)
-                       uart_resume_port(&sci_uart_driver, &p->port);
-       }
+       spin_unlock_irqrestore(&priv->lock, flags);
 
        return 0;
 }
@@ -1339,8 +1379,6 @@ static int __init sci_init(void)
 
        printk(banner);
 
-       sci_init_ports();
-
        ret = uart_register_driver(&sci_uart_driver);
        if (likely(ret == 0)) {
                ret = platform_driver_register(&sci_driver);
index d0aa82d7fce0930e9016a929300966c7bf4aa9f5..38072c15b845d5d2877f18fa1ed5fcb6fb5c12a0 100644 (file)
@@ -91,6 +91,9 @@
 # define SCSPTR5                0xa4050128
 # define SCIF_ORER              0x0001  /* overrun error bit */
 # define SCSCR_INIT(port)       0x0038  /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
+# define SCIF_ORER              0x0001  /* overrun error bit */
+# define SCSCR_INIT(port)       0x0038  /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
 #elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
 # define SCSPTR2 0xffe80020 /* 16 bit SCIF */
 # define SCIF_ORER 0x0001   /* overrun error bit */
     }                                                                  \
   }
 
-#define CPU_SCIF_FNS(name, scif_offset, scif_size)                             \
+#ifdef CONFIG_H8300
+/* h8300 don't have SCIF */
+#define CPU_SCIF_FNS(name)                                             \
+  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
+  {                                                                    \
+    return 0;                                                          \
+  }                                                                    \
+  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
+  {                                                                    \
+  }
+#else
+#define CPU_SCIF_FNS(name, scif_offset, scif_size)                     \
   static inline unsigned int sci_##name##_in(struct uart_port *port)   \
   {                                                                    \
     SCI_IN(scif_size, scif_offset);                                    \
   {                                                                    \
     SCI_OUT(scif_size, scif_offset, value);                            \
   }
+#endif
 
 #define CPU_SCI_FNS(name, sci_offset, sci_size)                                \
   static inline unsigned int sci_##name##_in(struct uart_port* port)   \
                 sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
                  h8_sci_offset, h8_sci_size) \
   CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+  CPU_SCIF_FNS(name)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
+      defined(CONFIG_CPU_SUBTYPE_SH7724)
         #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \
                 CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size)
         #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \
@@ -390,7 +407,8 @@ SCIF_FNS(SCFDR,  0x1c, 16)
 SCIF_FNS(SCxTDR, 0x20,  8)
 SCIF_FNS(SCxRDR, 0x24,  8)
 SCIF_FNS(SCLSR,  0x24, 16)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
+      defined(CONFIG_CPU_SUBTYPE_SH7724)
 SCIx_FNS(SCSMR,  0x00, 16, 0x00, 16)
 SCIx_FNS(SCBRR,  0x04,  8, 0x04,  8)
 SCIx_FNS(SCSCR,  0x08, 16, 0x08, 16)
@@ -604,10 +622,21 @@ static inline int sci_rxd_in(struct uart_port *port)
                 return ctrl_inb(SCSPTR5) & 0x0008 ? 1 : 0; /* SCIF5 */
         return 1;
 }
+#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
+#  define SCFSR    0x0010
+#  define SCASSR   0x0014
+static inline int sci_rxd_in(struct uart_port *port)
+{
+       if (port->type == PORT_SCIF)
+               return ctrl_inw((port->mapbase + SCFSR))  & SCIF_BRK ? 1 : 0;
+       if (port->type == PORT_SCIFA)
+               return ctrl_inw((port->mapbase + SCASSR)) & SCIF_BRK ? 1 : 0;
+       return 1;
+}
 #elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
 static inline int sci_rxd_in(struct uart_port *port)
 {
-         return sci_in(port, SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
+         return sci_in(port, SCSPTR)&0x0001 ? 1 : 0; /* SCIF */
 }
 #elif defined(__H8300H__) || defined(__H8300S__)
 static inline int sci_rxd_in(struct uart_port *port)
@@ -757,7 +786,8 @@ static inline int sci_rxd_in(struct uart_port *port)
       defined(CONFIG_CPU_SUBTYPE_SH7720) || \
       defined(CONFIG_CPU_SUBTYPE_SH7721)
 #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
+      defined(CONFIG_CPU_SUBTYPE_SH7724)
 static inline int scbrr_calc(struct uart_port *port, int bps, int clk)
 {
        if (port->type == PORT_SCIF)
diff --git a/drivers/serial/timbuart.c b/drivers/serial/timbuart.c
new file mode 100644 (file)
index 0000000..ac9e5d5
--- /dev/null
@@ -0,0 +1,526 @@
+/*
+ * timbuart.c timberdale FPGA UART driver
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Supports:
+ * Timberdale FPGA UART
+ */
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/serial_core.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
+
+#include "timbuart.h"
+
+struct timbuart_port {
+       struct uart_port        port;
+       struct tasklet_struct   tasklet;
+       int                     usedma;
+       u8                      last_ier;
+       struct platform_device  *dev;
+};
+
+static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800,
+       921600, 1843200, 3250000};
+
+static void timbuart_mctrl_check(struct uart_port *port, u8 isr, u8 *ier);
+
+static irqreturn_t timbuart_handleinterrupt(int irq, void *devid);
+
+static void timbuart_stop_rx(struct uart_port *port)
+{
+       /* spin lock held by upper layer, disable all RX interrupts */
+       u8 ier = ioread8(port->membase + TIMBUART_IER) & ~RXFLAGS;
+       iowrite8(ier, port->membase + TIMBUART_IER);
+}
+
+static void timbuart_stop_tx(struct uart_port *port)
+{
+       /* spinlock held by upper layer, disable TX interrupt */
+       u8 ier = ioread8(port->membase + TIMBUART_IER) & ~TXBAE;
+       iowrite8(ier, port->membase + TIMBUART_IER);
+}
+
+static void timbuart_start_tx(struct uart_port *port)
+{
+       struct timbuart_port *uart =
+               container_of(port, struct timbuart_port, port);
+
+       /* do not transfer anything here -> fire off the tasklet */
+       tasklet_schedule(&uart->tasklet);
+}
+
+static void timbuart_flush_buffer(struct uart_port *port)
+{
+       u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | TIMBUART_CTRL_FLSHTX;
+
+       iowrite8(ctl, port->membase + TIMBUART_CTRL);
+       iowrite8(TXBF, port->membase + TIMBUART_ISR);
+}
+
+static void timbuart_rx_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = port->info->port.tty;
+
+       while (ioread8(port->membase + TIMBUART_ISR) & RXDP) {
+               u8 ch = ioread8(port->membase + TIMBUART_RXFIFO);
+               port->icount.rx++;
+               tty_insert_flip_char(tty, ch, TTY_NORMAL);
+       }
+
+       spin_unlock(&port->lock);
+       tty_flip_buffer_push(port->info->port.tty);
+       spin_lock(&port->lock);
+
+       dev_dbg(port->dev, "%s - total read %d bytes\n",
+               __func__, port->icount.rx);
+}
+
+static void timbuart_tx_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->info->xmit;
+
+       while (!(ioread8(port->membase + TIMBUART_ISR) & TXBF) &&
+               !uart_circ_empty(xmit)) {
+               iowrite8(xmit->buf[xmit->tail],
+                       port->membase + TIMBUART_TXFIFO);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+
+       dev_dbg(port->dev,
+               "%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n",
+                __func__,
+               port->icount.tx,
+               ioread8(port->membase + TIMBUART_CTRL),
+               port->mctrl & TIOCM_RTS,
+               ioread8(port->membase + TIMBUART_BAUDRATE));
+}
+
+static void timbuart_handle_tx_port(struct uart_port *port, u8 isr, u8 *ier)
+{
+       struct timbuart_port *uart =
+               container_of(port, struct timbuart_port, port);
+       struct circ_buf *xmit = &port->info->xmit;
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+               return;
+
+       if (port->x_char)
+               return;
+
+       if (isr & TXFLAGS) {
+               timbuart_tx_chars(port);
+               /* clear all TX interrupts */
+               iowrite8(TXFLAGS, port->membase + TIMBUART_ISR);
+
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(port);
+       } else
+               /* Re-enable any tx interrupt */
+               *ier |= uart->last_ier & TXFLAGS;
+
+       /* enable interrupts if there are chars in the transmit buffer,
+        * Or if we delivered some bytes and want the almost empty interrupt
+        * we wake up the upper layer later when we got the interrupt
+        * to give it some time to go out...
+        */
+       if (!uart_circ_empty(xmit))
+               *ier |= TXBAE;
+
+       dev_dbg(port->dev, "%s - leaving\n", __func__);
+}
+
+void timbuart_handle_rx_port(struct uart_port *port, u8 isr, u8 *ier)
+{
+       if (isr & RXFLAGS) {
+               /* Some RX status is set */
+               if (isr & RXBF) {
+                       u8 ctl = ioread8(port->membase + TIMBUART_CTRL) |
+                               TIMBUART_CTRL_FLSHRX;
+                       iowrite8(ctl, port->membase + TIMBUART_CTRL);
+                       port->icount.overrun++;
+               } else if (isr & (RXDP))
+                       timbuart_rx_chars(port);
+
+               /* ack all RX interrupts */
+               iowrite8(RXFLAGS, port->membase + TIMBUART_ISR);
+       }
+
+       /* always have the RX interrupts enabled */
+       *ier |= RXBAF | RXBF | RXTT;
+
+       dev_dbg(port->dev, "%s - leaving\n", __func__);
+}
+
+void timbuart_tasklet(unsigned long arg)
+{
+       struct timbuart_port *uart = (struct timbuart_port *)arg;
+       u8 isr, ier = 0;
+
+       spin_lock(&uart->port.lock);
+
+       isr = ioread8(uart->port.membase + TIMBUART_ISR);
+       dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr);
+
+       if (!uart->usedma)
+               timbuart_handle_tx_port(&uart->port, isr, &ier);
+
+       timbuart_mctrl_check(&uart->port, isr, &ier);
+
+       if (!uart->usedma)
+               timbuart_handle_rx_port(&uart->port, isr, &ier);
+
+       iowrite8(ier, uart->port.membase + TIMBUART_IER);
+
+       spin_unlock(&uart->port.lock);
+       dev_dbg(uart->port.dev, "%s leaving\n", __func__);
+}
+
+static unsigned int timbuart_tx_empty(struct uart_port *port)
+{
+       u8 isr = ioread8(port->membase + TIMBUART_ISR);
+
+       return (isr & TXBAE) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int timbuart_get_mctrl(struct uart_port *port)
+{
+       u8 cts = ioread8(port->membase + TIMBUART_CTRL);
+       dev_dbg(port->dev, "%s - cts %x\n", __func__, cts);
+
+       if (cts & TIMBUART_CTRL_CTS)
+               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+       else
+               return TIOCM_DSR | TIOCM_CAR;
+}
+
+static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       dev_dbg(port->dev, "%s - %x\n", __func__, mctrl);
+
+       if (mctrl & TIOCM_RTS)
+               iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL);
+       else
+               iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL);
+}
+
+static void timbuart_mctrl_check(struct uart_port *port, u8 isr, u8 *ier)
+{
+       unsigned int cts;
+
+       if (isr & CTS_DELTA) {
+               /* ack */
+               iowrite8(CTS_DELTA, port->membase + TIMBUART_ISR);
+               cts = timbuart_get_mctrl(port);
+               uart_handle_cts_change(port, cts & TIOCM_CTS);
+               wake_up_interruptible(&port->info->delta_msr_wait);
+       }
+
+       *ier |= CTS_DELTA;
+}
+
+static void timbuart_enable_ms(struct uart_port *port)
+{
+       /* N/A */
+}
+
+static void timbuart_break_ctl(struct uart_port *port, int ctl)
+{
+       /* N/A */
+}
+
+static int timbuart_startup(struct uart_port *port)
+{
+       struct timbuart_port *uart =
+               container_of(port, struct timbuart_port, port);
+
+       dev_dbg(port->dev, "%s\n", __func__);
+
+       iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL);
+       iowrite8(0xff, port->membase + TIMBUART_ISR);
+       /* Enable all but TX interrupts */
+       iowrite8(RXBAF | RXBF | RXTT | CTS_DELTA,
+               port->membase + TIMBUART_IER);
+
+       return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED,
+               "timb-uart", uart);
+}
+
+static void timbuart_shutdown(struct uart_port *port)
+{
+       struct timbuart_port *uart =
+               container_of(port, struct timbuart_port, port);
+       dev_dbg(port->dev, "%s\n", __func__);
+       free_irq(port->irq, uart);
+       iowrite8(0, port->membase + TIMBUART_IER);
+}
+
+static int get_bindex(int baud)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(baudrates); i++)
+               if (baud <= baudrates[i])
+                       return i;
+
+       return -1;
+}
+
+static void timbuart_set_termios(struct uart_port *port,
+       struct ktermios *termios,
+       struct ktermios *old)
+{
+       unsigned int baud;
+       short bindex;
+       unsigned long flags;
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+       bindex = get_bindex(baud);
+       dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex);
+
+       if (bindex < 0)
+               bindex = 0;
+       baud = baudrates[bindex];
+
+       /* The serial layer calls into this once with old = NULL when setting
+          up initially */
+       if (old)
+               tty_termios_copy_hw(termios, old);
+       tty_termios_encode_baud_rate(termios, baud, baud);
+
+       spin_lock_irqsave(&port->lock, flags);
+       iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE);
+       uart_update_timeout(port, termios->c_cflag, baud);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *timbuart_type(struct uart_port *port)
+{
+       return port->type == PORT_UNKNOWN ? "timbuart" : NULL;
+}
+
+/* We do not request/release mappings of the registers here,
+ * currently it's done in the proble function.
+ */
+static void timbuart_release_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       int size =
+               resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
+
+       if (port->flags & UPF_IOREMAP) {
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+
+       release_mem_region(port->mapbase, size);
+}
+
+static int timbuart_request_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       int size =
+               resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
+
+       if (!request_mem_region(port->mapbase, size, "timb-uart"))
+               return -EBUSY;
+
+       if (port->flags & UPF_IOREMAP) {
+               port->membase = ioremap(port->mapbase, size);
+               if (port->membase == NULL) {
+                       release_mem_region(port->mapbase, size);
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+static irqreturn_t timbuart_handleinterrupt(int irq, void *devid)
+{
+       struct timbuart_port *uart = (struct timbuart_port *)devid;
+
+       if (ioread8(uart->port.membase + TIMBUART_IPR)) {
+               uart->last_ier = ioread8(uart->port.membase + TIMBUART_IER);
+
+               /* disable interrupts, the tasklet enables them again */
+               iowrite8(0, uart->port.membase + TIMBUART_IER);
+
+               /* fire off bottom half */
+               tasklet_schedule(&uart->tasklet);
+
+               return IRQ_HANDLED;
+       } else
+               return IRQ_NONE;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void timbuart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_TIMBUART;
+               timbuart_request_port(port);
+       }
+}
+
+static int timbuart_verify_port(struct uart_port *port,
+       struct serial_struct *ser)
+{
+       /* we don't want the core code to modify any port params */
+       return -EINVAL;
+}
+
+static struct uart_ops timbuart_ops = {
+       .tx_empty = timbuart_tx_empty,
+       .set_mctrl = timbuart_set_mctrl,
+       .get_mctrl = timbuart_get_mctrl,
+       .stop_tx = timbuart_stop_tx,
+       .start_tx = timbuart_start_tx,
+       .flush_buffer = timbuart_flush_buffer,
+       .stop_rx = timbuart_stop_rx,
+       .enable_ms = timbuart_enable_ms,
+       .break_ctl = timbuart_break_ctl,
+       .startup = timbuart_startup,
+       .shutdown = timbuart_shutdown,
+       .set_termios = timbuart_set_termios,
+       .type = timbuart_type,
+       .release_port = timbuart_release_port,
+       .request_port = timbuart_request_port,
+       .config_port = timbuart_config_port,
+       .verify_port = timbuart_verify_port
+};
+
+static struct uart_driver timbuart_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = "timberdale_uart",
+       .dev_name = "ttyTU",
+       .major = TIMBUART_MAJOR,
+       .minor = TIMBUART_MINOR,
+       .nr = 1
+};
+
+static int timbuart_probe(struct platform_device *dev)
+{
+       int err;
+       struct timbuart_port *uart;
+       struct resource *iomem;
+
+       dev_dbg(&dev->dev, "%s\n", __func__);
+
+       uart = kzalloc(sizeof(*uart), GFP_KERNEL);
+       if (!uart) {
+               err = -EINVAL;
+               goto err_mem;
+       }
+
+       uart->usedma = 0;
+
+       uart->port.uartclk = 3250000 * 16;
+       uart->port.fifosize  = TIMBUART_FIFO_SIZE;
+       uart->port.regshift  = 2;
+       uart->port.iotype  = UPIO_MEM;
+       uart->port.ops = &timbuart_ops;
+       uart->port.irq = 0;
+       uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+       uart->port.line  = 0;
+       uart->port.dev  = &dev->dev;
+
+       iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!iomem) {
+               err = -ENOMEM;
+               goto err_register;
+       }
+       uart->port.mapbase = iomem->start;
+       uart->port.membase = NULL;
+
+       uart->port.irq = platform_get_irq(dev, 0);
+       if (uart->port.irq < 0) {
+               err = -EINVAL;
+               goto err_register;
+       }
+
+       tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart);
+
+       err = uart_register_driver(&timbuart_driver);
+       if (err)
+               goto err_register;
+
+       err = uart_add_one_port(&timbuart_driver, &uart->port);
+       if (err)
+               goto err_add_port;
+
+       platform_set_drvdata(dev, uart);
+
+       return 0;
+
+err_add_port:
+       uart_unregister_driver(&timbuart_driver);
+err_register:
+       kfree(uart);
+err_mem:
+       printk(KERN_ERR "timberdale: Failed to register Timberdale UART: %d\n",
+               err);
+
+       return err;
+}
+
+static int timbuart_remove(struct platform_device *dev)
+{
+       struct timbuart_port *uart = platform_get_drvdata(dev);
+
+       tasklet_kill(&uart->tasklet);
+       uart_remove_one_port(&timbuart_driver, &uart->port);
+       uart_unregister_driver(&timbuart_driver);
+       kfree(uart);
+
+       return 0;
+}
+
+static struct platform_driver timbuart_platform_driver = {
+       .driver = {
+               .name   = "timb-uart",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = timbuart_probe,
+       .remove         = timbuart_remove,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init timbuart_init(void)
+{
+       return platform_driver_register(&timbuart_platform_driver);
+}
+
+static void __exit timbuart_exit(void)
+{
+       platform_driver_unregister(&timbuart_platform_driver);
+}
+
+module_init(timbuart_init);
+module_exit(timbuart_exit);
+
+MODULE_DESCRIPTION("Timberdale UART driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:timb-uart");
+
diff --git a/drivers/serial/timbuart.h b/drivers/serial/timbuart.h
new file mode 100644 (file)
index 0000000..7e56676
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * timbuart.c timberdale FPGA GPIO driver
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Supports:
+ * Timberdale FPGA UART
+ */
+
+#ifndef _TIMBUART_H
+#define _TIMBUART_H
+
+#define TIMBUART_FIFO_SIZE     2048
+
+#define TIMBUART_RXFIFO                0x08
+#define TIMBUART_TXFIFO                0x0c
+#define TIMBUART_IER           0x10
+#define TIMBUART_IPR           0x14
+#define TIMBUART_ISR           0x18
+#define TIMBUART_CTRL          0x1c
+#define TIMBUART_BAUDRATE      0x20
+
+#define TIMBUART_CTRL_RTS      0x01
+#define TIMBUART_CTRL_CTS      0x02
+#define TIMBUART_CTRL_FLSHTX   0x40
+#define TIMBUART_CTRL_FLSHRX   0x80
+
+#define TXBF           0x01
+#define TXBAE          0x02
+#define CTS_DELTA      0x04
+#define RXDP           0x08
+#define RXBAF          0x10
+#define RXBF           0x20
+#define RXTT           0x40
+#define RXBNAE         0x80
+#define TXBE           0x100
+
+#define RXFLAGS (RXDP | RXBAF | RXBF | RXTT | RXBNAE)
+#define TXFLAGS (TXBF | TXBAE)
+
+#define TIMBUART_MAJOR 204
+#define TIMBUART_MINOR 192
+
+#endif /* _TIMBUART_H */
+
index 12d13d99b6f09690c9ec31a42ae630f460f039f4..d687a9b93d03bac737e02d02ce4d292fd1ef018d 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/sh_intc.h>
 #include <linux/sysdev.h>
 #include <linux/list.h>
+#include <linux/topology.h>
 
 #define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
        ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
@@ -770,11 +771,19 @@ void __init register_intc_controller(struct intc_desc *desc)
        /* register the vectors one by one */
        for (i = 0; i < desc->nr_vectors; i++) {
                struct intc_vect *vect = desc->vectors + i;
+               unsigned int irq = evt2irq(vect->vect);
+               struct irq_desc *irq_desc;
 
                if (!vect->enum_id)
                        continue;
 
-               intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect));
+               irq_desc = irq_to_desc_alloc_node(irq, numa_node_id());
+               if (unlikely(!irq_desc)) {
+                       printk(KERN_INFO "can not get irq_desc for %d\n", irq);
+                       continue;
+               }
+
+               intc_register_irq(desc, d, vect->enum_id, irq);
        }
 }
 
index 7a1164dd1d37f4bf115b236ef088fe8c90a82f50..ddeb6919253734ebcb3b7a92b6294b30bb305d52 100644 (file)
@@ -16,7 +16,8 @@
  *     v0.9  - thorough cleaning, URBification, almost a rewrite
  *     v0.10 - some more cleanups
  *     v0.11 - fixed flow control, read error doesn't stop reads
- *     v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced
+ *     v0.12 - added TIOCM ioctls, added break handling, made struct acm
+ *             kmalloced
  *     v0.13 - added termios, added hangup
  *     v0.14 - sized down struct acm
  *     v0.15 - fixed flow control again - characters could be lost
@@ -62,7 +63,7 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb/cdc.h>
 #include <asm/byteorder.h>
@@ -87,7 +88,10 @@ static struct acm *acm_table[ACM_TTY_MINORS];
 
 static DEFINE_MUTEX(open_mutex);
 
-#define ACM_READY(acm) (acm && acm->dev && acm->used)
+#define ACM_READY(acm) (acm && acm->dev && acm->port.count)
+
+static const struct tty_port_operations acm_port_ops = {
+};
 
 #ifdef VERBOSE_DEBUG
 #define verbose        1
@@ -99,13 +103,15 @@ static DEFINE_MUTEX(open_mutex);
  * Functions for ACM control messages.
  */
 
-static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len)
+static int acm_ctrl_msg(struct acm *acm, int request, int value,
+                                                       void *buf, int len)
 {
        int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
                request, USB_RT_ACM, value,
                acm->control->altsetting[0].desc.bInterfaceNumber,
                buf, len, 5000);
-       dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
+       dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d",
+                                               request, value, len, retval);
        return retval < 0 ? retval : 0;
 }
 
@@ -150,9 +156,8 @@ static int acm_wb_is_avail(struct acm *acm)
 
        n = ACM_NW;
        spin_lock_irqsave(&acm->write_lock, flags);
-       for (i = 0; i < ACM_NW; i++) {
+       for (i = 0; i < ACM_NW; i++)
                n -= acm->wb[i].use;
-       }
        spin_unlock_irqrestore(&acm->write_lock, flags);
        return n;
 }
@@ -183,7 +188,8 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
        wb->urb->transfer_buffer_length = wb->len;
        wb->urb->dev = acm->dev;
 
-       if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) {
+       rc = usb_submit_urb(wb->urb, GFP_ATOMIC);
+       if (rc < 0) {
                dbg("usb_submit_urb(write bulk) failed: %d", rc);
                acm_write_done(acm, wb);
        }
@@ -262,6 +268,7 @@ static void acm_ctrl_irq(struct urb *urb)
 {
        struct acm *acm = urb->context;
        struct usb_cdc_notification *dr = urb->transfer_buffer;
+       struct tty_struct *tty;
        unsigned char *data;
        int newctrl;
        int retval;
@@ -287,40 +294,45 @@ static void acm_ctrl_irq(struct urb *urb)
 
        data = (unsigned char *)(dr + 1);
        switch (dr->bNotificationType) {
+       case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+               dbg("%s network", dr->wValue ?
+                                       "connected to" : "disconnected from");
+               break;
 
-               case USB_CDC_NOTIFY_NETWORK_CONNECTION:
-
-                       dbg("%s network", dr->wValue ? "connected to" : "disconnected from");
-                       break;
-
-               case USB_CDC_NOTIFY_SERIAL_STATE:
-
-                       newctrl = get_unaligned_le16(data);
+       case USB_CDC_NOTIFY_SERIAL_STATE:
+               tty = tty_port_tty_get(&acm->port);
+               newctrl = get_unaligned_le16(data);
 
-                       if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
+               if (tty) {
+                       if (!acm->clocal &&
+                               (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
                                dbg("calling hangup");
-                               tty_hangup(acm->tty);
+                               tty_hangup(tty);
                        }
+                       tty_kref_put(tty);
+               }
 
-                       acm->ctrlin = newctrl;
-
-                       dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
-                               acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
-                               acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI  ? '+' : '-',
-                               acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',     acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
-                               acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
+               acm->ctrlin = newctrl;
 
+               dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
+                       acm->ctrlin & ACM_CTRL_DCD ? '+' : '-',
+                       acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
+                       acm->ctrlin & ACM_CTRL_BRK ? '+' : '-',
+                       acm->ctrlin & ACM_CTRL_RI  ? '+' : '-',
+                       acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',
+                       acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
+                       acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
                        break;
 
-               default:
-                       dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
-                               dr->bNotificationType, dr->wIndex,
-                               dr->wLength, data[0], data[1]);
-                       break;
+       default:
+               dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
+                       dr->bNotificationType, dr->wIndex,
+                       dr->wLength, data[0], data[1]);
+               break;
        }
 exit:
        usb_mark_last_busy(acm->dev);
-       retval = usb_submit_urb (urb, GFP_ATOMIC);
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
        if (retval)
                dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with "
                        "result %d", __func__, retval);
@@ -371,15 +383,14 @@ static void acm_rx_tasklet(unsigned long _acm)
 {
        struct acm *acm = (void *)_acm;
        struct acm_rb *buf;
-       struct tty_struct *tty = acm->tty;
+       struct tty_struct *tty;
        struct acm_ru *rcv;
        unsigned long flags;
        unsigned char throttled;
 
        dbg("Entering acm_rx_tasklet");
 
-       if (!ACM_READY(acm))
-       {
+       if (!ACM_READY(acm)) {
                dbg("acm_rx_tasklet: ACM not ready");
                return;
        }
@@ -387,12 +398,13 @@ static void acm_rx_tasklet(unsigned long _acm)
        spin_lock_irqsave(&acm->throttle_lock, flags);
        throttled = acm->throttle;
        spin_unlock_irqrestore(&acm->throttle_lock, flags);
-       if (throttled)
-       {
+       if (throttled) {
                dbg("acm_rx_tasklet: throttled");
                return;
        }
 
+       tty = tty_port_tty_get(&acm->port);
+
 next_buffer:
        spin_lock_irqsave(&acm->read_lock, flags);
        if (list_empty(&acm->filled_read_bufs)) {
@@ -406,20 +418,22 @@ next_buffer:
 
        dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
 
-       tty_buffer_request_room(tty, buf->size);
-       spin_lock_irqsave(&acm->throttle_lock, flags);
-       throttled = acm->throttle;
-       spin_unlock_irqrestore(&acm->throttle_lock, flags);
-       if (!throttled)
-               tty_insert_flip_string(tty, buf->base, buf->size);
-       tty_flip_buffer_push(tty);
-
-       if (throttled) {
-               dbg("Throttling noticed");
-               spin_lock_irqsave(&acm->read_lock, flags);
-               list_add(&buf->list, &acm->filled_read_bufs);
-               spin_unlock_irqrestore(&acm->read_lock, flags);
-               return;
+       if (tty) {
+               spin_lock_irqsave(&acm->throttle_lock, flags);
+               throttled = acm->throttle;
+               spin_unlock_irqrestore(&acm->throttle_lock, flags);
+               if (!throttled) {
+                       tty_buffer_request_room(tty, buf->size);
+                       tty_insert_flip_string(tty, buf->base, buf->size);
+                       tty_flip_buffer_push(tty);
+               } else {
+                       tty_kref_put(tty);
+                       dbg("Throttling noticed");
+                       spin_lock_irqsave(&acm->read_lock, flags);
+                       list_add(&buf->list, &acm->filled_read_bufs);
+                       spin_unlock_irqrestore(&acm->read_lock, flags);
+                       return;
+               }
        }
 
        spin_lock_irqsave(&acm->read_lock, flags);
@@ -428,6 +442,8 @@ next_buffer:
        goto next_buffer;
 
 urbs:
+       tty_kref_put(tty);
+
        while (!list_empty(&acm->spare_read_bufs)) {
                spin_lock_irqsave(&acm->read_lock, flags);
                if (list_empty(&acm->spare_read_urbs)) {
@@ -454,10 +470,11 @@ urbs:
                rcv->urb->transfer_dma = buf->dma;
                rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
-               /* This shouldn't kill the driver as unsuccessful URBs are returned to the
-                  free-urbs-pool and resubmited ASAP */
+               /* This shouldn't kill the driver as unsuccessful URBs are
+                  returned to the free-urbs-pool and resubmited ASAP */
                spin_lock_irqsave(&acm->read_lock, flags);
-               if (acm->susp_count || usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
+               if (acm->susp_count ||
+                               usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
                        list_add(&buf->list, &acm->spare_read_bufs);
                        list_add(&rcv->list, &acm->spare_read_urbs);
                        acm->processing = 0;
@@ -499,11 +516,14 @@ static void acm_write_bulk(struct urb *urb)
 static void acm_softint(struct work_struct *work)
 {
        struct acm *acm = container_of(work, struct acm, work);
+       struct tty_struct *tty;
 
        dev_vdbg(&acm->data->dev, "tx work\n");
        if (!ACM_READY(acm))
                return;
-       tty_wakeup(acm->tty);
+       tty = tty_port_tty_get(&acm->port);
+       tty_wakeup(tty);
+       tty_kref_put(tty);
 }
 
 static void acm_waker(struct work_struct *waker)
@@ -543,8 +563,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
                rv = 0;
 
        set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
+
        tty->driver_data = acm;
-       acm->tty = tty;
+       tty_port_tty_set(&acm->port, tty);
 
        if (usb_autopm_get_interface(acm->control) < 0)
                goto early_bail;
@@ -552,11 +573,10 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
                acm->control->needs_remote_wakeup = 1;
 
        mutex_lock(&acm->mutex);
-       if (acm->used++) {
+       if (acm->port.count++) {
                usb_autopm_put_interface(acm->control);
                goto done;
-        }
-
+       }
 
        acm->ctrlurb->dev = acm->dev;
        if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
@@ -567,22 +587,22 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
        if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
            (acm->ctrl_caps & USB_CDC_CAP_LINE))
                goto full_bailout;
+
        usb_autopm_put_interface(acm->control);
 
        INIT_LIST_HEAD(&acm->spare_read_urbs);
        INIT_LIST_HEAD(&acm->spare_read_bufs);
        INIT_LIST_HEAD(&acm->filled_read_bufs);
-       for (i = 0; i < acm->rx_buflimit; i++) {
+
+       for (i = 0; i < acm->rx_buflimit; i++)
                list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
-       }
-       for (i = 0; i < acm->rx_buflimit; i++) {
+       for (i = 0; i < acm->rx_buflimit; i++)
                list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
-       }
 
        acm->throttle = 0;
 
        tasklet_schedule(&acm->urb_task);
-
+       rv = tty_port_block_til_ready(&acm->port, tty, filp);
 done:
        mutex_unlock(&acm->mutex);
 err_out:
@@ -593,16 +613,17 @@ full_bailout:
        usb_kill_urb(acm->ctrlurb);
 bail_out:
        usb_autopm_put_interface(acm->control);
-       acm->used--;
+       acm->port.count--;
        mutex_unlock(&acm->mutex);
 early_bail:
        mutex_unlock(&open_mutex);
+       tty_port_tty_set(&acm->port, NULL);
        return -EIO;
 }
 
 static void acm_tty_unregister(struct acm *acm)
 {
-       int i,nr;
+       int i, nr;
 
        nr = acm->rx_buflimit;
        tty_unregister_device(acm_tty_driver, acm->minor);
@@ -619,41 +640,56 @@ static void acm_tty_unregister(struct acm *acm)
 
 static int acm_tty_chars_in_buffer(struct tty_struct *tty);
 
+static void acm_port_down(struct acm *acm, int drain)
+{
+       int i, nr = acm->rx_buflimit;
+       mutex_lock(&open_mutex);
+       if (acm->dev) {
+               usb_autopm_get_interface(acm->control);
+               acm_set_control(acm, acm->ctrlout = 0);
+               /* try letting the last writes drain naturally */
+               if (drain) {
+                       wait_event_interruptible_timeout(acm->drain_wait,
+                               (ACM_NW == acm_wb_is_avail(acm)) || !acm->dev,
+                                       ACM_CLOSE_TIMEOUT * HZ);
+               }
+               usb_kill_urb(acm->ctrlurb);
+               for (i = 0; i < ACM_NW; i++)
+                       usb_kill_urb(acm->wb[i].urb);
+               for (i = 0; i < nr; i++)
+                       usb_kill_urb(acm->ru[i].urb);
+               acm->control->needs_remote_wakeup = 0;
+               usb_autopm_put_interface(acm->control);
+       }
+       mutex_unlock(&open_mutex);
+}
+
+static void acm_tty_hangup(struct tty_struct *tty)
+{
+       struct acm *acm = tty->driver_data;
+       tty_port_hangup(&acm->port);
+       acm_port_down(acm, 0);
+}
+
 static void acm_tty_close(struct tty_struct *tty, struct file *filp)
 {
        struct acm *acm = tty->driver_data;
-       int i,nr;
 
-       if (!acm || !acm->used)
+       /* Perform the closing process and see if we need to do the hardware
+          shutdown */
+       if (tty_port_close_start(&acm->port, tty, filp) == 0)
                return;
-
-       nr = acm->rx_buflimit;
+       acm_port_down(acm, 0);
+       tty_port_close_end(&acm->port, tty);
        mutex_lock(&open_mutex);
-       if (!--acm->used) {
-               if (acm->dev) {
-                       usb_autopm_get_interface(acm->control);
-                       acm_set_control(acm, acm->ctrlout = 0);
-
-                       /* try letting the last writes drain naturally */
-                       wait_event_interruptible_timeout(acm->drain_wait,
-                                       (ACM_NW == acm_wb_is_avail(acm))
-                                               || !acm->dev,
-                                       ACM_CLOSE_TIMEOUT * HZ);
-
-                       usb_kill_urb(acm->ctrlurb);
-                       for (i = 0; i < ACM_NW; i++)
-                               usb_kill_urb(acm->wb[i].urb);
-                       for (i = 0; i < nr; i++)
-                               usb_kill_urb(acm->ru[i].urb);
-                       acm->control->needs_remote_wakeup = 0;
-                       usb_autopm_put_interface(acm->control);
-               } else
-                       acm_tty_unregister(acm);
-       }
+       tty_port_tty_set(&acm->port, NULL);
+       if (!acm->dev)
+               acm_tty_unregister(acm);
        mutex_unlock(&open_mutex);
 }
 
-static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
+static int acm_tty_write(struct tty_struct *tty,
+                                       const unsigned char *buf, int count)
 {
        struct acm *acm = tty->driver_data;
        int stat;
@@ -669,7 +705,8 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
                return 0;
 
        spin_lock_irqsave(&acm->write_lock, flags);
-       if ((wbn = acm_wb_alloc(acm)) < 0) {
+       wbn = acm_wb_alloc(acm);
+       if (wbn < 0) {
                spin_unlock_irqrestore(&acm->write_lock, flags);
                return 0;
        }
@@ -681,7 +718,8 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
        wb->len = count;
        spin_unlock_irqrestore(&acm->write_lock, flags);
 
-       if ((stat = acm_write_start(acm, wbn)) < 0)
+       stat = acm_write_start(acm, wbn);
+       if (stat < 0)
                return stat;
        return count;
 }
@@ -767,8 +805,10 @@ static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
                return -EINVAL;
 
        newctrl = acm->ctrlout;
-       set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
-       clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
+       set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
+                                       (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
+       clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
+                                       (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
 
        newctrl = (newctrl & ~clear) | set;
 
@@ -777,7 +817,8 @@ static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
        return acm_set_control(acm, acm->ctrlout = newctrl);
 }
 
-static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+static int acm_tty_ioctl(struct tty_struct *tty, struct file *file,
+                                       unsigned int cmd, unsigned long arg)
 {
        struct acm *acm = tty->driver_data;
 
@@ -799,7 +840,8 @@ static const __u8 acm_tty_size[] = {
        5, 6, 7, 8
 };
 
-static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old)
+static void acm_tty_set_termios(struct tty_struct *tty,
+                                               struct ktermios *termios_old)
 {
        struct acm *acm = tty->driver_data;
        struct ktermios *termios = tty->termios;
@@ -809,19 +851,23 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios
        if (!ACM_READY(acm))
                return;
 
+       /* FIXME: Needs to support the tty_baud interface */
+       /* FIXME: Broken on sparc */
        newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
                (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
        newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
        newline.bParityType = termios->c_cflag & PARENB ?
-               (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
+                               (termios->c_cflag & PARODD ? 1 : 2) +
+                               (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
        newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
-
+       /* FIXME: Needs to clear unsupported bits in the termios */
        acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
 
        if (!newline.dwDTERate) {
                newline.dwDTERate = acm->line.dwDTERate;
                newctrl &= ~ACM_CTRL_DTR;
-       } else  newctrl |=  ACM_CTRL_DTR;
+       } else
+               newctrl |=  ACM_CTRL_DTR;
 
        if (newctrl != acm->ctrlout)
                acm_set_control(acm, acm->ctrlout = newctrl);
@@ -846,9 +892,8 @@ static void acm_write_buffers_free(struct acm *acm)
        struct acm_wb *wb;
        struct usb_device *usb_dev = interface_to_usbdev(acm->control);
 
-       for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
+       for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++)
                usb_buffer_free(usb_dev, acm->writesize, wb->buf, wb->dmah);
-       }
 }
 
 static void acm_read_buffers_free(struct acm *acm)
@@ -857,7 +902,8 @@ static void acm_read_buffers_free(struct acm *acm)
        int i, n = acm->rx_buflimit;
 
        for (i = 0; i < n; i++)
-               usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
+               usb_buffer_free(usb_dev, acm->readsize,
+                                       acm->rb[i].base, acm->rb[i].dma);
 }
 
 /* Little helper: write buffers allocate */
@@ -882,8 +928,8 @@ static int acm_write_buffers_alloc(struct acm *acm)
        return 0;
 }
 
-static int acm_probe (struct usb_interface *intf,
-                     const struct usb_device_id *id)
+static int acm_probe(struct usb_interface *intf,
+                    const struct usb_device_id *id)
 {
        struct usb_cdc_union_desc *union_header = NULL;
        struct usb_cdc_country_functional_desc *cfd = NULL;
@@ -897,7 +943,7 @@ static int acm_probe (struct usb_interface *intf,
        struct usb_device *usb_dev = interface_to_usbdev(intf);
        struct acm *acm;
        int minor;
-       int ctrlsize,readsize;
+       int ctrlsize, readsize;
        u8 *buf;
        u8 ac_management_function = 0;
        u8 call_management_function = 0;
@@ -917,7 +963,7 @@ static int acm_probe (struct usb_interface *intf,
                control_interface = usb_ifnum_to_if(usb_dev, 0);
                goto skip_normal_probe;
        }
-       
+
        /* normal probing*/
        if (!buffer) {
                dev_err(&intf->dev, "Weird descriptor references\n");
@@ -925,8 +971,10 @@ static int acm_probe (struct usb_interface *intf,
        }
 
        if (!buflen) {
-               if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
-                       dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n");
+               if (intf->cur_altsetting->endpoint->extralen &&
+                               intf->cur_altsetting->endpoint->extra) {
+                       dev_dbg(&intf->dev,
+                               "Seeking extra descriptors on endpoint\n");
                        buflen = intf->cur_altsetting->endpoint->extralen;
                        buffer = intf->cur_altsetting->endpoint->extra;
                } else {
@@ -937,47 +985,43 @@ static int acm_probe (struct usb_interface *intf,
        }
 
        while (buflen > 0) {
-               if (buffer [1] != USB_DT_CS_INTERFACE) {
+               if (buffer[1] != USB_DT_CS_INTERFACE) {
                        dev_err(&intf->dev, "skipping garbage\n");
                        goto next_desc;
                }
 
-               switch (buffer [2]) {
-                       case USB_CDC_UNION_TYPE: /* we've found it */
-                               if (union_header) {
-                                       dev_err(&intf->dev, "More than one "
-                                               "union descriptor, "
-                                               "skipping ...\n");
-                                       goto next_desc;
-                               }
-                               union_header = (struct usb_cdc_union_desc *)
-                                                       buffer;
-                               break;
-                       case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
-                               cfd = (struct usb_cdc_country_functional_desc *)buffer;
-                               break;
-                       case USB_CDC_HEADER_TYPE: /* maybe check version */ 
-                               break; /* for now we ignore it */ 
-                       case USB_CDC_ACM_TYPE:
-                               ac_management_function = buffer[3];
-                               break;
-                       case USB_CDC_CALL_MANAGEMENT_TYPE:
-                               call_management_function = buffer[3];
-                               call_interface_num = buffer[4];
-                               if ((call_management_function & 3) != 3)
-                                       dev_err(&intf->dev, "This device "
-                                               "cannot do calls on its own. "
-                                               "It is no modem.\n");
-                               break;
-                       default:
-                               /* there are LOTS more CDC descriptors that
-                                * could legitimately be found here.
-                                */
-                               dev_dbg(&intf->dev, "Ignoring descriptor: "
-                                               "type %02x, length %d\n",
-                                               buffer[2], buffer[0]);
-                               break;
+               switch (buffer[2]) {
+               case USB_CDC_UNION_TYPE: /* we've found it */
+                       if (union_header) {
+                               dev_err(&intf->dev, "More than one "
+                                       "union descriptor, skipping ...\n");
+                               goto next_desc;
                        }
+                       union_header = (struct usb_cdc_union_desc *)buffer;
+                       break;
+               case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
+                       cfd = (struct usb_cdc_country_functional_desc *)buffer;
+                       break;
+               case USB_CDC_HEADER_TYPE: /* maybe check version */
+                       break; /* for now we ignore it */
+               case USB_CDC_ACM_TYPE:
+                       ac_management_function = buffer[3];
+                       break;
+               case USB_CDC_CALL_MANAGEMENT_TYPE:
+                       call_management_function = buffer[3];
+                       call_interface_num = buffer[4];
+                       if ((call_management_function & 3) != 3)
+                               dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
+                       break;
+               default:
+                       /* there are LOTS more CDC descriptors that
+                        * could legitimately be found here.
+                        */
+                       dev_dbg(&intf->dev, "Ignoring descriptor: "
+                                       "type %02x, length %d\n",
+                                       buffer[2], buffer[0]);
+                       break;
+               }
 next_desc:
                buflen -= buffer[0];
                buffer += buffer[0];
@@ -985,33 +1029,36 @@ next_desc:
 
        if (!union_header) {
                if (call_interface_num > 0) {
-                       dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n");
+                       dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
                        data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
                        control_interface = intf;
                } else {
-                       dev_dbg(&intf->dev,"No union descriptor, giving up\n");
+                       dev_dbg(&intf->dev,
+                                       "No union descriptor, giving up\n");
                        return -ENODEV;
                }
        } else {
                control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
                data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
                if (!control_interface || !data_interface) {
-                       dev_dbg(&intf->dev,"no interfaces\n");
+                       dev_dbg(&intf->dev, "no interfaces\n");
                        return -ENODEV;
                }
        }
-       
+
        if (data_interface_num != call_interface_num)
-               dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n");
+               dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");
 
 skip_normal_probe:
 
        /*workaround for switched interfaces */
-       if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
-               if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
+       if (data_interface->cur_altsetting->desc.bInterfaceClass
+                                               != CDC_DATA_INTERFACE_TYPE) {
+               if (control_interface->cur_altsetting->desc.bInterfaceClass
+                                               == CDC_DATA_INTERFACE_TYPE) {
                        struct usb_interface *t;
-                       dev_dbg(&intf->dev,"Your device has switched interfaces.\n");
-
+                       dev_dbg(&intf->dev,
+                               "Your device has switched interfaces.\n");
                        t = control_interface;
                        control_interface = data_interface;
                        data_interface = t;
@@ -1023,9 +1070,9 @@ skip_normal_probe:
        /* Accept probe requests only for the control interface */
        if (intf != control_interface)
                return -ENODEV;
-       
+
        if (usb_interface_claimed(data_interface)) { /* valid in this context */
-               dev_dbg(&intf->dev,"The data interface isn't available\n");
+               dev_dbg(&intf->dev, "The data interface isn't available\n");
                return -EBUSY;
        }
 
@@ -1042,8 +1089,8 @@ skip_normal_probe:
        if (!usb_endpoint_dir_in(epread)) {
                /* descriptors are swapped */
                struct usb_endpoint_descriptor *t;
-               dev_dbg(&intf->dev,"The data interface has switched endpoints\n");
-               
+               dev_dbg(&intf->dev,
+                       "The data interface has switched endpoints\n");
                t = epread;
                epread = epwrite;
                epwrite = t;
@@ -1056,13 +1103,15 @@ skip_normal_probe:
                return -ENODEV;
        }
 
-       if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
+       acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
+       if (acm == NULL) {
                dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
                goto alloc_fail;
        }
 
        ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
-       readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);
+       readsize = le16_to_cpu(epread->wMaxPacketSize) *
+                               (quirks == SINGLE_RX_URB ? 1 : 2);
        acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
        acm->control = control_interface;
        acm->data = data_interface;
@@ -1082,6 +1131,8 @@ skip_normal_probe:
        spin_lock_init(&acm->read_lock);
        mutex_init(&acm->mutex);
        acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
+       tty_port_init(&acm->port);
+       acm->port.ops = &acm_port_ops;
 
        buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
        if (!buf) {
@@ -1103,8 +1154,10 @@ skip_normal_probe:
        for (i = 0; i < num_rx_buf; i++) {
                struct acm_ru *rcv = &(acm->ru[i]);
 
-               if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
-                       dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n");
+               rcv->urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (rcv->urb == NULL) {
+                       dev_dbg(&intf->dev,
+                               "out of memory (read urbs usb_alloc_urb)\n");
                        goto alloc_fail7;
                }
 
@@ -1117,26 +1170,29 @@ skip_normal_probe:
                rb->base = usb_buffer_alloc(acm->dev, readsize,
                                GFP_KERNEL, &rb->dma);
                if (!rb->base) {
-                       dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
+                       dev_dbg(&intf->dev,
+                               "out of memory (read bufs usb_buffer_alloc)\n");
                        goto alloc_fail7;
                }
        }
-       for(i = 0; i < ACM_NW; i++)
-       {
+       for (i = 0; i < ACM_NW; i++) {
                struct acm_wb *snd = &(acm->wb[i]);
 
-               if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) {
-                       dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)");
+               snd->urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (snd->urb == NULL) {
+                       dev_dbg(&intf->dev,
+                               "out of memory (write urbs usb_alloc_urb)");
                        goto alloc_fail7;
                }
 
-               usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
-                               NULL, acm->writesize, acm_write_bulk, snd);
+               usb_fill_bulk_urb(snd->urb, usb_dev,
+                       usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
+                       NULL, acm->writesize, acm_write_bulk, snd);
                snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
                snd->instance = acm;
        }
 
-       usb_set_intfdata (intf, acm);
+       usb_set_intfdata(intf, acm);
 
        i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
        if (i < 0)
@@ -1147,7 +1203,8 @@ skip_normal_probe:
                if (!acm->country_codes)
                        goto skip_countries;
                acm->country_code_size = cfd->bLength - 4;
-               memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4);
+               memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0,
+                                                       cfd->bLength - 4);
                acm->country_rel_date = cfd->iCountryCodeRelDate;
 
                i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
@@ -1156,7 +1213,8 @@ skip_normal_probe:
                        goto skip_countries;
                }
 
-               i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
+               i = device_create_file(&intf->dev,
+                                               &dev_attr_iCountryCodeRelDate);
                if (i < 0) {
                        kfree(acm->country_codes);
                        goto skip_countries;
@@ -1164,8 +1222,10 @@ skip_normal_probe:
        }
 
 skip_countries:
-       usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
-                        acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
+       usb_fill_int_urb(acm->ctrlurb, usb_dev,
+                       usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
+                       acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
+                       epctrl->bInterval);
        acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
        acm->ctrlurb->transfer_dma = acm->ctrl_dma;
 
@@ -1212,7 +1272,7 @@ static void stop_data_traffic(struct acm *acm)
        tasklet_disable(&acm->urb_task);
 
        usb_kill_urb(acm->ctrlurb);
-       for(i = 0; i < ACM_NW; i++)
+       for (i = 0; i < ACM_NW; i++)
                usb_kill_urb(acm->wb[i].urb);
        for (i = 0; i < acm->rx_buflimit; i++)
                usb_kill_urb(acm->ru[i].urb);
@@ -1227,13 +1287,14 @@ static void acm_disconnect(struct usb_interface *intf)
 {
        struct acm *acm = usb_get_intfdata(intf);
        struct usb_device *usb_dev = interface_to_usbdev(intf);
+       struct tty_struct *tty;
 
        /* sibling interface is already cleaning up */
        if (!acm)
                return;
 
        mutex_lock(&open_mutex);
-       if (acm->country_codes){
+       if (acm->country_codes) {
                device_remove_file(&acm->control->dev,
                                &dev_attr_wCountryCodes);
                device_remove_file(&acm->control->dev,
@@ -1247,22 +1308,25 @@ static void acm_disconnect(struct usb_interface *intf)
        stop_data_traffic(acm);
 
        acm_write_buffers_free(acm);
-       usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
+       usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer,
+                                                               acm->ctrl_dma);
        acm_read_buffers_free(acm);
 
        usb_driver_release_interface(&acm_driver, intf == acm->control ?
                                        acm->data : acm->control);
 
-       if (!acm->used) {
+       if (acm->port.count == 0) {
                acm_tty_unregister(acm);
                mutex_unlock(&open_mutex);
                return;
        }
 
        mutex_unlock(&open_mutex);
-
-       if (acm->tty)
-               tty_hangup(acm->tty);
+       tty = tty_port_tty_get(&acm->port);
+       if (tty) {
+               tty_hangup(tty);
+               tty_kref_put(tty);
+       }
 }
 
 #ifdef CONFIG_PM
@@ -1297,7 +1361,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
        */
        mutex_lock(&acm->mutex);
 
-       if (acm->used)
+       if (acm->port.count)
                stop_data_traffic(acm);
 
        mutex_unlock(&acm->mutex);
@@ -1319,7 +1383,7 @@ static int acm_resume(struct usb_interface *intf)
                return 0;
 
        mutex_lock(&acm->mutex);
-       if (acm->used) {
+       if (acm->port.count) {
                rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
                if (rv < 0)
                        goto err_out;
@@ -1398,7 +1462,7 @@ static struct usb_device_id acm_ids[] = {
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
                USB_CDC_ACM_PROTO_AT_GSM) },
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
-               USB_CDC_ACM_PROTO_AT_3G ) },
+               USB_CDC_ACM_PROTO_AT_3G) },
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
                USB_CDC_ACM_PROTO_AT_CDMA) },
 
@@ -1406,7 +1470,7 @@ static struct usb_device_id acm_ids[] = {
        { }
 };
 
-MODULE_DEVICE_TABLE (usb, acm_ids);
+MODULE_DEVICE_TABLE(usb, acm_ids);
 
 static struct usb_driver acm_driver = {
        .name =         "cdc_acm",
@@ -1429,6 +1493,7 @@ static struct usb_driver acm_driver = {
 static const struct tty_operations acm_ops = {
        .open =                 acm_tty_open,
        .close =                acm_tty_close,
+       .hangup =               acm_tty_hangup,
        .write =                acm_tty_write,
        .write_room =           acm_tty_write_room,
        .ioctl =                acm_tty_ioctl,
@@ -1460,7 +1525,8 @@ static int __init acm_init(void)
        acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
        acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        acm_tty_driver->init_termios = tty_std_termios;
-       acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD |
+                                                               HUPCL | CLOCAL;
        tty_set_operations(acm_tty_driver, &acm_ops);
 
        retval = tty_register_driver(acm_tty_driver);
@@ -1492,7 +1558,7 @@ static void __exit acm_exit(void)
 module_init(acm_init);
 module_exit(acm_exit);
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR);
index 1f95e7aa1b665618bc1fa83f6b9977375a026298..4c3856420adde6c55761950e0697822d9e496d1b 100644 (file)
@@ -89,8 +89,8 @@ struct acm {
        struct usb_device *dev;                         /* the corresponding usb device */
        struct usb_interface *control;                  /* control interface */
        struct usb_interface *data;                     /* data interface */
-       struct tty_struct *tty;                         /* the corresponding tty */
-       struct urb *ctrlurb;                    /* urbs */
+       struct tty_port port;                           /* our tty port data */
+       struct urb *ctrlurb;                            /* urbs */
        u8 *ctrl_buffer;                                /* buffers of urbs */
        dma_addr_t ctrl_dma;                            /* dma handles of buffers */
        u8 *country_codes;                              /* country codes from device */
@@ -120,7 +120,6 @@ struct acm {
        unsigned int ctrlout;                           /* output control lines (DTR, RTS) */
        unsigned int writesize;                         /* max packet size for the output bulk endpoint */
        unsigned int readsize,ctrlsize;                 /* buffer sizes for freeing */
-       unsigned int used;                              /* someone has this acm's device open */
        unsigned int minor;                             /* acm minor number */
        unsigned char throttle;                         /* throttled by tty layer */
        unsigned char clocal;                           /* termios CLOCAL */
index b7eacad4d48cb4ae34097c8d2ebbe7cb0ad0a363..2bfd6dd85b5ad23624cef600a2e8e5f76de5fa18 100644 (file)
@@ -93,8 +93,7 @@ static int  belkin_sa_startup(struct usb_serial *serial);
 static void belkin_sa_shutdown(struct usb_serial *serial);
 static int  belkin_sa_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
-static void belkin_sa_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp);
+static void belkin_sa_close(struct usb_serial_port *port);
 static void belkin_sa_read_int_callback(struct urb *urb);
 static void belkin_sa_set_termios(struct tty_struct *tty,
                        struct usb_serial_port *port, struct ktermios * old);
@@ -244,8 +243,7 @@ exit:
 } /* belkin_sa_open */
 
 
-static void belkin_sa_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void belkin_sa_close(struct usb_serial_port *port)
 {
        dbg("%s port %d", __func__, port->number);
 
index ab4cc277aa659be685a154c6a5024cf02f14eba9..2830766f5b391cc7d177c82e49a058ba28b1be73 100644 (file)
@@ -262,13 +262,33 @@ error:    kfree(priv);
        return r;
 }
 
-static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port,
-                               struct file *filp)
+static int ch341_carrier_raised(struct usb_serial_port *port)
+{
+       struct ch341_private *priv = usb_get_serial_port_data(port);
+       if (priv->line_status & CH341_BIT_DCD)
+               return 1;
+       return 0;
+}
+
+static void ch341_dtr_rts(struct usb_serial_port *port, int on)
 {
        struct ch341_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
-       unsigned int c_cflag;
 
+       dbg("%s - port %d", __func__, port->number);
+       /* drop DTR and RTS */
+       spin_lock_irqsave(&priv->lock, flags);
+       if (on)
+               priv->line_control |= CH341_BIT_RTS | CH341_BIT_DTR;
+       else
+               priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
+       spin_unlock_irqrestore(&priv->lock, flags);
+       ch341_set_handshake(port->serial->dev, priv->line_control);
+       wake_up_interruptible(&priv->delta_msr_wait);
+}
+
+static void ch341_close(struct usb_serial_port *port)
+{
        dbg("%s - port %d", __func__, port->number);
 
        /* shutdown our urbs */
@@ -276,18 +296,6 @@ static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port,
        usb_kill_urb(port->write_urb);
        usb_kill_urb(port->read_urb);
        usb_kill_urb(port->interrupt_in_urb);
-
-       if (tty) {
-               c_cflag = tty->termios->c_cflag;
-               if (c_cflag & HUPCL) {
-                       /* drop DTR and RTS */
-                       spin_lock_irqsave(&priv->lock, flags);
-                       priv->line_control = 0;
-                       spin_unlock_irqrestore(&priv->lock, flags);
-                       ch341_set_handshake(port->serial->dev, 0);
-               }
-       }
-       wake_up_interruptible(&priv->delta_msr_wait);
 }
 
 
@@ -302,7 +310,6 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port,
        dbg("ch341_open()");
 
        priv->baud_rate = DEFAULT_BAUD_RATE;
-       priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
 
        r = ch341_configure(serial->dev, priv);
        if (r)
@@ -322,7 +329,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port,
        if (r) {
                dev_err(&port->dev, "%s - failed submitting interrupt urb,"
                        " error %d\n", __func__, r);
-               ch341_close(tty, port, NULL);
+               ch341_close(port);
                return -EPROTO;
        }
 
@@ -343,9 +350,6 @@ static void ch341_set_termios(struct tty_struct *tty,
 
        dbg("ch341_set_termios()");
 
-       if (!tty || !tty->termios)
-               return;
-
        baud_rate = tty_get_baud_rate(tty);
 
        priv->baud_rate = baud_rate;
@@ -568,6 +572,8 @@ static struct usb_serial_driver ch341_device = {
        .usb_driver        = &ch341_driver,
        .num_ports         = 1,
        .open              = ch341_open,
+       .dtr_rts           = ch341_dtr_rts,
+       .carrier_raised    = ch341_carrier_raised,
        .close             = ch341_close,
        .ioctl             = ch341_ioctl,
        .set_termios       = ch341_set_termios,
index 19e24045b137a2964b450afbf94cc930de3cd427..247b61bfb7f45f4d179abd6ef36f9611eea046da 100644 (file)
@@ -169,7 +169,9 @@ static int usb_console_setup(struct console *co, char *options)
                        kfree(tty);
                }
        }
-
+       /* So we know not to kill the hardware on a hangup on this
+          port. We have also bumped the use count by one so it won't go
+          idle */
        port->console = 1;
        retval = 0;
 
@@ -182,7 +184,7 @@ free_tty:
        kfree(tty);
 reset_open_count:
        port->port.count = 0;
-goto out;
+       goto out;
 }
 
 static void usb_console_write(struct console *co,
index e8d5133ce9c84f911d210a374f5af40821c7f6b4..16a154d3b2feeaaacf0e0c949405d992a66165be 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Silicon Laboratories CP2101/CP2102 USB to RS232 serial adaptor driver
+ * Silicon Laboratories CP210x USB to RS232 serial adaptor driver
  *
  * Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk)
  *
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.08"
-#define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver"
+#define DRIVER_VERSION "v0.09"
+#define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver"
 
 /*
  * Function Prototypes
  */
-static int cp2101_open(struct tty_struct *, struct usb_serial_port *,
+static int cp210x_open(struct tty_struct *, struct usb_serial_port *,
                                                        struct file *);
-static void cp2101_cleanup(struct usb_serial_port *);
-static void cp2101_close(struct tty_struct *, struct usb_serial_port *,
-                                                       struct file*);
-static void cp2101_get_termios(struct tty_struct *,
+static void cp210x_cleanup(struct usb_serial_port *);
+static void cp210x_close(struct usb_serial_port *);
+static void cp210x_get_termios(struct tty_struct *,
        struct usb_serial_port *port);
-static void cp2101_get_termios_port(struct usb_serial_port *port,
+static void cp210x_get_termios_port(struct usb_serial_port *port,
        unsigned int *cflagp, unsigned int *baudp);
-static void cp2101_set_termios(struct tty_struct *, struct usb_serial_port *,
+static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
                                                        struct ktermios*);
-static int cp2101_tiocmget(struct tty_struct *, struct file *);
-static int cp2101_tiocmset(struct tty_struct *, struct file *,
+static int cp210x_tiocmget(struct tty_struct *, struct file *);
+static int cp210x_tiocmset(struct tty_struct *, struct file *,
                unsigned int, unsigned int);
-static int cp2101_tiocmset_port(struct usb_serial_port *port, struct file *,
+static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *,
                unsigned int, unsigned int);
-static void cp2101_break_ctl(struct tty_struct *, int);
-static int cp2101_startup(struct usb_serial *);
-static void cp2101_shutdown(struct usb_serial *);
+static void cp210x_break_ctl(struct tty_struct *, int);
+static int cp210x_startup(struct usb_serial *);
+static void cp210x_shutdown(struct usb_serial *);
 
 static int debug;
 
 static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */
        { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
+       { USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */
        { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
+       { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
        { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
        { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */
        { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */
        { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
        { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
        { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
+       { USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */
        { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
        { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
        { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
@@ -85,10 +87,12 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
        { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
        { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
+       { USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */
        { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
        { USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */
        { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demostration module */
        { USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */
+       { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
        { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
        { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
        { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
@@ -99,7 +103,9 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */
        { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */
        { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
+       { USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */
        { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
+       { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */
        { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
        { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
        { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
@@ -108,53 +114,70 @@ static struct usb_device_id id_table [] = {
 
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver cp2101_driver = {
-       .name           = "cp2101",
+static struct usb_driver cp210x_driver = {
+       .name           = "cp210x",
        .probe          = usb_serial_probe,
        .disconnect     = usb_serial_disconnect,
        .id_table       = id_table,
        .no_dynamic_id  =       1,
 };
 
-static struct usb_serial_driver cp2101_device = {
+static struct usb_serial_driver cp210x_device = {
        .driver = {
                .owner =        THIS_MODULE,
-               .name =         "cp2101",
+               .name =         "cp210x",
        },
-       .usb_driver             = &cp2101_driver,
+       .usb_driver             = &cp210x_driver,
        .id_table               = id_table,
        .num_ports              = 1,
-       .open                   = cp2101_open,
-       .close                  = cp2101_close,
-       .break_ctl              = cp2101_break_ctl,
-       .set_termios            = cp2101_set_termios,
-       .tiocmget               = cp2101_tiocmget,
-       .tiocmset               = cp2101_tiocmset,
-       .attach                 = cp2101_startup,
-       .shutdown               = cp2101_shutdown,
+       .open                   = cp210x_open,
+       .close                  = cp210x_close,
+       .break_ctl              = cp210x_break_ctl,
+       .set_termios            = cp210x_set_termios,
+       .tiocmget               = cp210x_tiocmget,
+       .tiocmset               = cp210x_tiocmset,
+       .attach                 = cp210x_startup,
+       .shutdown               = cp210x_shutdown,
 };
 
 /* Config request types */
 #define REQTYPE_HOST_TO_DEVICE 0x41
 #define REQTYPE_DEVICE_TO_HOST 0xc1
 
-/* Config SET requests. To GET, add 1 to the request number */
-#define CP2101_UART            0x00    /* Enable / Disable */
-#define CP2101_BAUDRATE                0x01    /* (BAUD_RATE_GEN_FREQ / baudrate) */
-#define CP2101_BITS            0x03    /* 0x(0)(databits)(parity)(stopbits) */
-#define CP2101_BREAK           0x05    /* On / Off */
-#define CP2101_CONTROL         0x07    /* Flow control line states */
-#define CP2101_MODEMCTL                0x13    /* Modem controls */
-#define CP2101_CONFIG_6                0x19    /* 6 bytes of config data ??? */
-
-/* CP2101_UART */
+/* Config request codes */
+#define CP210X_IFC_ENABLE      0x00
+#define CP210X_SET_BAUDDIV     0x01
+#define CP210X_GET_BAUDDIV     0x02
+#define CP210X_SET_LINE_CTL    0x03
+#define CP210X_GET_LINE_CTL    0x04
+#define CP210X_SET_BREAK       0x05
+#define CP210X_IMM_CHAR                0x06
+#define CP210X_SET_MHS         0x07
+#define CP210X_GET_MDMSTS      0x08
+#define CP210X_SET_XON         0x09
+#define CP210X_SET_XOFF                0x0A
+#define CP210X_SET_EVENTMASK   0x0B
+#define CP210X_GET_EVENTMASK   0x0C
+#define CP210X_SET_CHAR                0x0D
+#define CP210X_GET_CHARS       0x0E
+#define CP210X_GET_PROPS       0x0F
+#define CP210X_GET_COMM_STATUS 0x10
+#define CP210X_RESET           0x11
+#define CP210X_PURGE           0x12
+#define CP210X_SET_FLOW                0x13
+#define CP210X_GET_FLOW                0x14
+#define CP210X_EMBED_EVENTS    0x15
+#define CP210X_GET_EVENTSTATE  0x16
+#define CP210X_SET_CHARS       0x19
+
+/* CP210X_IFC_ENABLE */
 #define UART_ENABLE            0x0001
 #define UART_DISABLE           0x0000
 
-/* CP2101_BAUDRATE */
+/* CP210X_(SET|GET)_BAUDDIV */
 #define BAUD_RATE_GEN_FREQ     0x384000
 
-/* CP2101_BITS */
+/* CP210X_(SET|GET)_LINE_CTL */
 #define BITS_DATA_MASK         0X0f00
 #define BITS_DATA_5            0X0500
 #define BITS_DATA_6            0X0600
@@ -174,11 +197,11 @@ static struct usb_serial_driver cp2101_device = {
 #define BITS_STOP_1_5          0x0001
 #define BITS_STOP_2            0x0002
 
-/* CP2101_BREAK */
+/* CP210X_SET_BREAK */
 #define BREAK_ON               0x0000
 #define BREAK_OFF              0x0001
 
-/* CP2101_CONTROL */
+/* CP210X_(SET_MHS|GET_MDMSTS) */
 #define CONTROL_DTR            0x0001
 #define CONTROL_RTS            0x0002
 #define CONTROL_CTS            0x0010
@@ -189,13 +212,13 @@ static struct usb_serial_driver cp2101_device = {
 #define CONTROL_WRITE_RTS      0x0200
 
 /*
- * cp2101_get_config
- * Reads from the CP2101 configuration registers
+ * cp210x_get_config
+ * Reads from the CP210x configuration registers
  * 'size' is specified in bytes.
  * 'data' is a pointer to a pre-allocated array of integers large
  * enough to hold 'size' bytes (with 4 bytes to each integer)
  */
-static int cp2101_get_config(struct usb_serial_port *port, u8 request,
+static int cp210x_get_config(struct usb_serial_port *port, u8 request,
                unsigned int *data, int size)
 {
        struct usb_serial *serial = port->serial;
@@ -211,9 +234,6 @@ static int cp2101_get_config(struct usb_serial_port *port, u8 request,
                return -ENOMEM;
        }
 
-       /* For get requests, the request number must be incremented */
-       request++;
-
        /* Issue the request, attempting to read 'size' bytes */
        result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                                request, REQTYPE_DEVICE_TO_HOST, 0x0000,
@@ -236,12 +256,12 @@ static int cp2101_get_config(struct usb_serial_port *port, u8 request,
 }
 
 /*
- * cp2101_set_config
- * Writes to the CP2101 configuration registers
+ * cp210x_set_config
+ * Writes to the CP210x configuration registers
  * Values less than 16 bits wide are sent directly
  * 'size' is specified in bytes.
  */
-static int cp2101_set_config(struct usb_serial_port *port, u8 request,
+static int cp210x_set_config(struct usb_serial_port *port, u8 request,
                unsigned int *data, int size)
 {
        struct usb_serial *serial = port->serial;
@@ -292,21 +312,21 @@ static int cp2101_set_config(struct usb_serial_port *port, u8 request,
 }
 
 /*
- * cp2101_set_config_single
- * Convenience function for calling cp2101_set_config on single data values
+ * cp210x_set_config_single
+ * Convenience function for calling cp210x_set_config on single data values
  * without requiring an integer pointer
  */
-static inline int cp2101_set_config_single(struct usb_serial_port *port,
+static inline int cp210x_set_config_single(struct usb_serial_port *port,
                u8 request, unsigned int data)
 {
-       return cp2101_set_config(port, request, &data, 2);
+       return cp210x_set_config(port, request, &data, 2);
 }
 
 /*
- * cp2101_quantise_baudrate
+ * cp210x_quantise_baudrate
  * Quantises the baud rate as per AN205 Table 1
  */
-static unsigned int cp2101_quantise_baudrate(unsigned int baud) {
+static unsigned int cp210x_quantise_baudrate(unsigned int baud) {
        if      (baud <= 56)       baud = 0;
        else if (baud <= 300)      baud = 300;
        else if (baud <= 600)      baud = 600;
@@ -343,7 +363,7 @@ static unsigned int cp2101_quantise_baudrate(unsigned int baud) {
        return baud;
 }
 
-static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port,
+static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port,
                                struct file *filp)
 {
        struct usb_serial *serial = port->serial;
@@ -351,7 +371,7 @@ static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port,
 
        dbg("%s - port %d", __func__, port->number);
 
-       if (cp2101_set_config_single(port, CP2101_UART, UART_ENABLE)) {
+       if (cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE)) {
                dev_err(&port->dev, "%s - Unable to enable UART\n",
                                __func__);
                return -EPROTO;
@@ -373,17 +393,17 @@ static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port,
        }
 
        /* Configure the termios structure */
-       cp2101_get_termios(tty, port);
+       cp210x_get_termios(tty, port);
 
        /* Set the DTR and RTS pins low */
-       cp2101_tiocmset_port(tty ? (struct usb_serial_port *) tty->driver_data
+       cp210x_tiocmset_port(tty ? (struct usb_serial_port *) tty->driver_data
                        : port,
                NULL, TIOCM_DTR | TIOCM_RTS, 0);
 
        return 0;
 }
 
-static void cp2101_cleanup(struct usb_serial_port *port)
+static void cp210x_cleanup(struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
 
@@ -398,8 +418,7 @@ static void cp2101_cleanup(struct usb_serial_port *port)
        }
 }
 
-static void cp2101_close(struct tty_struct *tty, struct usb_serial_port *port,
-                                       struct file *filp)
+static void cp210x_close(struct usb_serial_port *port)
 {
        dbg("%s - port %d", __func__, port->number);
 
@@ -410,23 +429,23 @@ static void cp2101_close(struct tty_struct *tty, struct usb_serial_port *port,
 
        mutex_lock(&port->serial->disc_mutex);
        if (!port->serial->disconnected)
-               cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
+               cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
        mutex_unlock(&port->serial->disc_mutex);
 }
 
 /*
- * cp2101_get_termios
+ * cp210x_get_termios
  * Reads the baud rate, data bits, parity, stop bits and flow control mode
  * from the device, corrects any unsupported values, and configures the
  * termios structure to reflect the state of the device
  */
-static void cp2101_get_termios(struct tty_struct *tty,
+static void cp210x_get_termios(struct tty_struct *tty,
        struct usb_serial_port *port)
 {
        unsigned int baud;
 
        if (tty) {
-               cp2101_get_termios_port(tty->driver_data,
+               cp210x_get_termios_port(tty->driver_data,
                        &tty->termios->c_cflag, &baud);
                tty_encode_baud_rate(tty, baud, baud);
        }
@@ -434,15 +453,15 @@ static void cp2101_get_termios(struct tty_struct *tty,
        else {
                unsigned int cflag;
                cflag = 0;
-               cp2101_get_termios_port(port, &cflag, &baud);
+               cp210x_get_termios_port(port, &cflag, &baud);
        }
 }
 
 /*
- * cp2101_get_termios_port
- * This is the heart of cp2101_get_termios which always uses a &usb_serial_port.
+ * cp210x_get_termios_port
+ * This is the heart of cp210x_get_termios which always uses a &usb_serial_port.
  */
-static void cp2101_get_termios_port(struct usb_serial_port *port,
+static void cp210x_get_termios_port(struct usb_serial_port *port,
        unsigned int *cflagp, unsigned int *baudp)
 {
        unsigned int cflag, modem_ctl[4];
@@ -451,17 +470,17 @@ static void cp2101_get_termios_port(struct usb_serial_port *port,
 
        dbg("%s - port %d", __func__, port->number);
 
-       cp2101_get_config(port, CP2101_BAUDRATE, &baud, 2);
+       cp210x_get_config(port, CP210X_GET_BAUDDIV, &baud, 2);
        /* Convert to baudrate */
        if (baud)
-               baud = cp2101_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud);
+               baud = cp210x_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud);
 
        dbg("%s - baud rate = %d", __func__, baud);
        *baudp = baud;
 
        cflag = *cflagp;
 
-       cp2101_get_config(port, CP2101_BITS, &bits, 2);
+       cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
        cflag &= ~CSIZE;
        switch (bits & BITS_DATA_MASK) {
        case BITS_DATA_5:
@@ -486,14 +505,14 @@ static void cp2101_get_termios_port(struct usb_serial_port *port,
                cflag |= CS8;
                bits &= ~BITS_DATA_MASK;
                bits |= BITS_DATA_8;
-               cp2101_set_config(port, CP2101_BITS, &bits, 2);
+               cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
                break;
        default:
                dbg("%s - Unknown number of data bits, using 8", __func__);
                cflag |= CS8;
                bits &= ~BITS_DATA_MASK;
                bits |= BITS_DATA_8;
-               cp2101_set_config(port, CP2101_BITS, &bits, 2);
+               cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
                break;
        }
 
@@ -516,20 +535,20 @@ static void cp2101_get_termios_port(struct usb_serial_port *port,
                                __func__);
                cflag &= ~PARENB;
                bits &= ~BITS_PARITY_MASK;
-               cp2101_set_config(port, CP2101_BITS, &bits, 2);
+               cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
                break;
        case BITS_PARITY_SPACE:
                dbg("%s - parity = SPACE (not supported, disabling parity)",
                                __func__);
                cflag &= ~PARENB;
                bits &= ~BITS_PARITY_MASK;
-               cp2101_set_config(port, CP2101_BITS, &bits, 2);
+               cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
                break;
        default:
                dbg("%s - Unknown parity mode, disabling parity", __func__);
                cflag &= ~PARENB;
                bits &= ~BITS_PARITY_MASK;
-               cp2101_set_config(port, CP2101_BITS, &bits, 2);
+               cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
                break;
        }
 
@@ -542,7 +561,7 @@ static void cp2101_get_termios_port(struct usb_serial_port *port,
                dbg("%s - stop bits = 1.5 (not supported, using 1 stop bit)",
                                                                __func__);
                bits &= ~BITS_STOP_MASK;
-               cp2101_set_config(port, CP2101_BITS, &bits, 2);
+               cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
                break;
        case BITS_STOP_2:
                dbg("%s - stop bits = 2", __func__);
@@ -552,11 +571,11 @@ static void cp2101_get_termios_port(struct usb_serial_port *port,
                dbg("%s - Unknown number of stop bits, using 1 stop bit",
                                                                __func__);
                bits &= ~BITS_STOP_MASK;
-               cp2101_set_config(port, CP2101_BITS, &bits, 2);
+               cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
                break;
        }
 
-       cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16);
+       cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16);
        if (modem_ctl[0] & 0x0008) {
                dbg("%s - flow control = CRTSCTS", __func__);
                cflag |= CRTSCTS;
@@ -568,7 +587,7 @@ static void cp2101_get_termios_port(struct usb_serial_port *port,
        *cflagp = cflag;
 }
 
-static void cp2101_set_termios(struct tty_struct *tty,
+static void cp210x_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios)
 {
        unsigned int cflag, old_cflag;
@@ -583,13 +602,13 @@ static void cp2101_set_termios(struct tty_struct *tty,
        tty->termios->c_cflag &= ~CMSPAR;
        cflag = tty->termios->c_cflag;
        old_cflag = old_termios->c_cflag;
-       baud = cp2101_quantise_baudrate(tty_get_baud_rate(tty));
+       baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty));
 
        /* If the baud rate is to be updated*/
        if (baud != tty_termios_baud_rate(old_termios) && baud != 0) {
                dbg("%s - Setting baud rate to %d baud", __func__,
                                baud);
-               if (cp2101_set_config_single(port, CP2101_BAUDRATE,
+               if (cp210x_set_config_single(port, CP210X_SET_BAUDDIV,
                                        ((BAUD_RATE_GEN_FREQ + baud/2) / baud))) {
                        dbg("Baud rate requested not supported by device\n");
                        baud = tty_termios_baud_rate(old_termios);
@@ -600,7 +619,7 @@ static void cp2101_set_termios(struct tty_struct *tty,
 
        /* If the number of data bits is to be updated */
        if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
-               cp2101_get_config(port, CP2101_BITS, &bits, 2);
+               cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
                bits &= ~BITS_DATA_MASK;
                switch (cflag & CSIZE) {
                case CS5:
@@ -624,19 +643,19 @@ static void cp2101_set_termios(struct tty_struct *tty,
                        dbg("%s - data bits = 9", __func__);
                        break;*/
                default:
-                       dbg("cp2101 driver does not "
+                       dbg("cp210x driver does not "
                                        "support the number of bits requested,"
                                        " using 8 bit mode\n");
                                bits |= BITS_DATA_8;
                                break;
                }
-               if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
+               if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
                        dbg("Number of data bits requested "
                                        "not supported by device\n");
        }
 
        if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) {
-               cp2101_get_config(port, CP2101_BITS, &bits, 2);
+               cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
                bits &= ~BITS_PARITY_MASK;
                if (cflag & PARENB) {
                        if (cflag & PARODD) {
@@ -647,13 +666,13 @@ static void cp2101_set_termios(struct tty_struct *tty,
                                dbg("%s - parity = EVEN", __func__);
                        }
                }
-               if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
+               if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
                        dbg("Parity mode not supported "
                                        "by device\n");
        }
 
        if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
-               cp2101_get_config(port, CP2101_BITS, &bits, 2);
+               cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
                bits &= ~BITS_STOP_MASK;
                if (cflag & CSTOPB) {
                        bits |= BITS_STOP_2;
@@ -662,13 +681,13 @@ static void cp2101_set_termios(struct tty_struct *tty,
                        bits |= BITS_STOP_1;
                        dbg("%s - stop bits = 1", __func__);
                }
-               if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
+               if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
                        dbg("Number of stop bits requested "
                                        "not supported by device\n");
        }
 
        if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
-               cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16);
+               cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16);
                dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
                                __func__, modem_ctl[0], modem_ctl[1],
                                modem_ctl[2], modem_ctl[3]);
@@ -688,19 +707,19 @@ static void cp2101_set_termios(struct tty_struct *tty,
                dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
                                __func__, modem_ctl[0], modem_ctl[1],
                                modem_ctl[2], modem_ctl[3]);
-               cp2101_set_config(port, CP2101_MODEMCTL, modem_ctl, 16);
+               cp210x_set_config(port, CP210X_SET_FLOW, modem_ctl, 16);
        }
 
 }
 
-static int cp2101_tiocmset (struct tty_struct *tty, struct file *file,
+static int cp210x_tiocmset (struct tty_struct *tty, struct file *file,
                unsigned int set, unsigned int clear)
 {
        struct usb_serial_port *port = tty->driver_data;
-       return cp2101_tiocmset_port(port, file, set, clear);
+       return cp210x_tiocmset_port(port, file, set, clear);
 }
 
-static int cp2101_tiocmset_port(struct usb_serial_port *port, struct file *file,
+static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *file,
                unsigned int set, unsigned int clear)
 {
        unsigned int control = 0;
@@ -726,10 +745,10 @@ static int cp2101_tiocmset_port(struct usb_serial_port *port, struct file *file,
 
        dbg("%s - control = 0x%.4x", __func__, control);
 
-       return cp2101_set_config(port, CP2101_CONTROL, &control, 2);
+       return cp210x_set_config(port, CP210X_SET_MHS, &control, 2);
 }
 
-static int cp2101_tiocmget (struct tty_struct *tty, struct file *file)
+static int cp210x_tiocmget (struct tty_struct *tty, struct file *file)
 {
        struct usb_serial_port *port = tty->driver_data;
        unsigned int control;
@@ -737,7 +756,7 @@ static int cp2101_tiocmget (struct tty_struct *tty, struct file *file)
 
        dbg("%s - port %d", __func__, port->number);
 
-       cp2101_get_config(port, CP2101_CONTROL, &control, 1);
+       cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1);
 
        result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
                |((control & CONTROL_RTS) ? TIOCM_RTS : 0)
@@ -751,7 +770,7 @@ static int cp2101_tiocmget (struct tty_struct *tty, struct file *file)
        return result;
 }
 
-static void cp2101_break_ctl (struct tty_struct *tty, int break_state)
+static void cp210x_break_ctl (struct tty_struct *tty, int break_state)
 {
        struct usb_serial_port *port = tty->driver_data;
        unsigned int state;
@@ -763,17 +782,17 @@ static void cp2101_break_ctl (struct tty_struct *tty, int break_state)
                state = BREAK_ON;
        dbg("%s - turning break %s", __func__,
                        state == BREAK_OFF ? "off" : "on");
-       cp2101_set_config(port, CP2101_BREAK, &state, 2);
+       cp210x_set_config(port, CP210X_SET_BREAK, &state, 2);
 }
 
-static int cp2101_startup(struct usb_serial *serial)
+static int cp210x_startup(struct usb_serial *serial)
 {
-       /* CP2101 buffers behave strangely unless device is reset */
+       /* cp210x buffers behave strangely unless device is reset */
        usb_reset_device(serial->dev);
        return 0;
 }
 
-static void cp2101_shutdown(struct usb_serial *serial)
+static void cp210x_shutdown(struct usb_serial *serial)
 {
        int i;
 
@@ -781,21 +800,21 @@ static void cp2101_shutdown(struct usb_serial *serial)
 
        /* Stop reads and writes on all ports */
        for (i = 0; i < serial->num_ports; ++i)
-               cp2101_cleanup(serial->port[i]);
+               cp210x_cleanup(serial->port[i]);
 }
 
-static int __init cp2101_init(void)
+static int __init cp210x_init(void)
 {
        int retval;
 
-       retval = usb_serial_register(&cp2101_device);
+       retval = usb_serial_register(&cp210x_device);
        if (retval)
                return retval; /* Failed to register */
 
-       retval = usb_register(&cp2101_driver);
+       retval = usb_register(&cp210x_driver);
        if (retval) {
                /* Failed to register */
-               usb_serial_deregister(&cp2101_device);
+               usb_serial_deregister(&cp210x_device);
                return retval;
        }
 
@@ -805,14 +824,14 @@ static int __init cp2101_init(void)
        return 0;
 }
 
-static void __exit cp2101_exit(void)
+static void __exit cp210x_exit(void)
 {
-       usb_deregister(&cp2101_driver);
-       usb_serial_deregister(&cp2101_device);
+       usb_deregister(&cp210x_driver);
+       usb_serial_deregister(&cp210x_device);
 }
 
-module_init(cp2101_init);
-module_exit(cp2101_exit);
+module_init(cp210x_init);
+module_exit(cp210x_exit);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
index dd501bb63ed6173b2b1f31a35f93d3a7d202db0a..933ba913e66c5fc21950a3ccc2e5b8229f8c9d63 100644 (file)
@@ -61,8 +61,7 @@ static int cyberjack_startup(struct usb_serial *serial);
 static void cyberjack_shutdown(struct usb_serial *serial);
 static int  cyberjack_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
-static void cyberjack_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp);
+static void cyberjack_close(struct usb_serial_port *port);
 static int cyberjack_write(struct tty_struct *tty,
        struct usb_serial_port *port, const unsigned char *buf, int count);
 static int cyberjack_write_room(struct tty_struct *tty);
@@ -185,8 +184,7 @@ static int  cyberjack_open(struct tty_struct *tty,
        return result;
 }
 
-static void cyberjack_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void cyberjack_close(struct usb_serial_port *port)
 {
        dbg("%s - port %d", __func__, port->number);
 
index e568710b263fa9dc6a6e258c6898c70254180d59..669f93848539560182b589131cc18788487477dc 100644 (file)
@@ -174,8 +174,8 @@ static int  cypress_ca42v2_startup(struct usb_serial *serial);
 static void cypress_shutdown(struct usb_serial *serial);
 static int  cypress_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
-static void cypress_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp);
+static void cypress_close(struct usb_serial_port *port);
+static void cypress_dtr_rts(struct usb_serial_port *port, int on);
 static int  cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
                        const unsigned char *buf, int count);
 static void cypress_send(struct usb_serial_port *port);
@@ -218,6 +218,7 @@ static struct usb_serial_driver cypress_earthmate_device = {
        .shutdown =                     cypress_shutdown,
        .open =                         cypress_open,
        .close =                        cypress_close,
+       .dtr_rts =                      cypress_dtr_rts,
        .write =                        cypress_write,
        .write_room =                   cypress_write_room,
        .ioctl =                        cypress_ioctl,
@@ -244,6 +245,7 @@ static struct usb_serial_driver cypress_hidcom_device = {
        .shutdown =                     cypress_shutdown,
        .open =                         cypress_open,
        .close =                        cypress_close,
+       .dtr_rts =                      cypress_dtr_rts,
        .write =                        cypress_write,
        .write_room =                   cypress_write_room,
        .ioctl =                        cypress_ioctl,
@@ -270,6 +272,7 @@ static struct usb_serial_driver cypress_ca42v2_device = {
        .shutdown =                     cypress_shutdown,
        .open =                         cypress_open,
        .close =                        cypress_close,
+       .dtr_rts =                      cypress_dtr_rts,
        .write =                        cypress_write,
        .write_room =                   cypress_write_room,
        .ioctl =                        cypress_ioctl,
@@ -656,11 +659,7 @@ static int cypress_open(struct tty_struct *tty,
        priv->rx_flags = 0;
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       /* raise both lines and set termios */
-       spin_lock_irqsave(&priv->lock, flags);
-       priv->line_control = CONTROL_DTR | CONTROL_RTS;
-       priv->cmd_ctrl = 1;
-       spin_unlock_irqrestore(&priv->lock, flags);
+       /* Set termios */
        result = cypress_write(tty, port, NULL, 0);
 
        if (result) {
@@ -694,76 +693,42 @@ static int cypress_open(struct tty_struct *tty,
                                                        __func__, result);
                cypress_set_dead(port);
        }
-
+       port->port.drain_delay = 256;
        return result;
 } /* cypress_open */
 
+static void cypress_dtr_rts(struct usb_serial_port *port, int on)
+{
+       struct cypress_private *priv = usb_get_serial_port_data(port);
+       /* drop dtr and rts */
+       priv = usb_get_serial_port_data(port);
+       spin_lock_irq(&priv->lock);
+       if (on == 0)
+               priv->line_control = 0;
+       else 
+               priv->line_control = CONTROL_DTR | CONTROL_RTS;
+       priv->cmd_ctrl = 1;
+       spin_unlock_irq(&priv->lock);
+       cypress_write(NULL, port, NULL, 0);
+}
 
-static void cypress_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void cypress_close(struct usb_serial_port *port)
 {
        struct cypress_private *priv = usb_get_serial_port_data(port);
-       unsigned int c_cflag;
-       int bps;
-       long timeout;
-       wait_queue_t wait;
 
        dbg("%s - port %d", __func__, port->number);
 
-       /* wait for data to drain from buffer */
-       spin_lock_irq(&priv->lock);
-       timeout = CYPRESS_CLOSING_WAIT;
-       init_waitqueue_entry(&wait, current);
-       add_wait_queue(&tty->write_wait, &wait);
-       for (;;) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (cypress_buf_data_avail(priv->buf) == 0
-               || timeout == 0 || signal_pending(current)
-               /* without mutex, allowed due to harmless failure mode */
-               || port->serial->disconnected)
-                       break;
-               spin_unlock_irq(&priv->lock);
-               timeout = schedule_timeout(timeout);
-               spin_lock_irq(&priv->lock);
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&tty->write_wait, &wait);
-       /* clear out any remaining data in the buffer */
-       cypress_buf_clear(priv->buf);
-       spin_unlock_irq(&priv->lock);
-
        /* writing is potentially harmful, lock must be taken */
        mutex_lock(&port->serial->disc_mutex);
        if (port->serial->disconnected) {
                mutex_unlock(&port->serial->disc_mutex);
                return;
        }
-       /* wait for characters to drain from device */
-       if (tty) {
-               bps = tty_get_baud_rate(tty);
-               if (bps > 1200)
-                       timeout = max((HZ * 2560) / bps, HZ / 10);
-               else
-                       timeout = 2 * HZ;
-               schedule_timeout_interruptible(timeout);
-       }
-
+       cypress_buf_clear(priv->buf);
        dbg("%s - stopping urbs", __func__);
        usb_kill_urb(port->interrupt_in_urb);
        usb_kill_urb(port->interrupt_out_urb);
 
-       if (tty) {
-               c_cflag = tty->termios->c_cflag;
-               if (c_cflag & HUPCL) {
-                       /* drop dtr and rts */
-                       priv = usb_get_serial_port_data(port);
-                       spin_lock_irq(&priv->lock);
-                       priv->line_control = 0;
-                       priv->cmd_ctrl = 1;
-                       spin_unlock_irq(&priv->lock);
-                       cypress_write(tty, port, NULL, 0);
-               }
-       }
 
        if (stats)
                dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
index 38ba4ea8b6bfdf1b84b69d9338cd9c3154d60e51..30f5140eff03a3bbeef50e90f28c942223c99e0e 100644 (file)
@@ -422,7 +422,6 @@ struct digi_port {
        int dp_throttled;
        int dp_throttle_restart;
        wait_queue_head_t dp_flush_wait;
-       int dp_in_close;                        /* close in progress */
        wait_queue_head_t dp_close_wait;        /* wait queue for close */
        struct work_struct dp_wakeup_work;
        struct usb_serial_port *dp_port;
@@ -456,8 +455,9 @@ static int digi_write_room(struct tty_struct *tty);
 static int digi_chars_in_buffer(struct tty_struct *tty);
 static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
        struct file *filp);
-static void digi_close(struct tty_struct *tty, struct usb_serial_port *port,
-       struct file *filp);
+static void digi_close(struct usb_serial_port *port);
+static int digi_carrier_raised(struct usb_serial_port *port);
+static void digi_dtr_rts(struct usb_serial_port *port, int on);
 static int digi_startup_device(struct usb_serial *serial);
 static int digi_startup(struct usb_serial *serial);
 static void digi_shutdown(struct usb_serial *serial);
@@ -510,6 +510,8 @@ static struct usb_serial_driver digi_acceleport_2_device = {
        .num_ports =                    3,
        .open =                         digi_open,
        .close =                        digi_close,
+       .dtr_rts =                      digi_dtr_rts,
+       .carrier_raised =               digi_carrier_raised,
        .write =                        digi_write,
        .write_room =                   digi_write_room,
        .write_bulk_callback =          digi_write_bulk_callback,
@@ -1328,6 +1330,19 @@ static int digi_chars_in_buffer(struct tty_struct *tty)
 
 }
 
+static void digi_dtr_rts(struct usb_serial_port *port, int on)
+{
+       /* Adjust DTR and RTS */
+       digi_set_modem_signals(port, on * (TIOCM_DTR|TIOCM_RTS), 1);
+}
+
+static int digi_carrier_raised(struct usb_serial_port *port)
+{
+       struct digi_port *priv = usb_get_serial_port_data(port);
+       if (priv->dp_modem_signals & TIOCM_CD)
+               return 1;
+       return 0;
+}
 
 static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
                                struct file *filp)
@@ -1336,7 +1351,6 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
        unsigned char buf[32];
        struct digi_port *priv = usb_get_serial_port_data(port);
        struct ktermios not_termios;
-       unsigned long flags = 0;
 
        dbg("digi_open: TOP: port=%d, open_count=%d",
                priv->dp_port_num, port->port.count);
@@ -1345,26 +1359,6 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
        if (digi_startup_device(port->serial) != 0)
                return -ENXIO;
 
-       spin_lock_irqsave(&priv->dp_port_lock, flags);
-
-       /* don't wait on a close in progress for non-blocking opens */
-       if (priv->dp_in_close && (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) {
-               spin_unlock_irqrestore(&priv->dp_port_lock, flags);
-               return -EAGAIN;
-       }
-
-       /* wait for a close in progress to finish */
-       while (priv->dp_in_close) {
-               cond_wait_interruptible_timeout_irqrestore(
-                       &priv->dp_close_wait, DIGI_RETRY_TIMEOUT,
-                       &priv->dp_port_lock, flags);
-               if (signal_pending(current))
-                       return -EINTR;
-               spin_lock_irqsave(&priv->dp_port_lock, flags);
-       }
-
-       spin_unlock_irqrestore(&priv->dp_port_lock, flags);
-
        /* read modem signals automatically whenever they change */
        buf[0] = DIGI_CMD_READ_INPUT_SIGNALS;
        buf[1] = priv->dp_port_num;
@@ -1387,16 +1381,11 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
                not_termios.c_iflag = ~tty->termios->c_iflag;
                digi_set_termios(tty, port, &not_termios);
        }
-
-       /* set DTR and RTS */
-       digi_set_modem_signals(port, TIOCM_DTR|TIOCM_RTS, 1);
-
        return 0;
 }
 
 
-static void digi_close(struct tty_struct *tty, struct usb_serial_port *port,
-                               struct file *filp)
+static void digi_close(struct usb_serial_port *port)
 {
        DEFINE_WAIT(wait);
        int ret;
@@ -1411,28 +1400,9 @@ static void digi_close(struct tty_struct *tty, struct usb_serial_port *port,
        if (port->serial->disconnected)
                goto exit;
 
-       /* do cleanup only after final close on this port */
-       spin_lock_irq(&priv->dp_port_lock);
-       priv->dp_in_close = 1;
-       spin_unlock_irq(&priv->dp_port_lock);
-
-       /* tell line discipline to process only XON/XOFF */
-       tty->closing = 1;
-
-       /* wait for output to drain */
-       if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0)
-               tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT);
-
-       /* flush driver and line discipline buffers */
-       tty_driver_flush_buffer(tty);
-       tty_ldisc_flush(tty);
-
        if (port->serial->dev) {
-               /* wait for transmit idle */
-               if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0)
-                       digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);
-               /* drop DTR and RTS */
-               digi_set_modem_signals(port, 0, 0);
+               /* FIXME: Transmit idle belongs in the wait_unti_sent path */
+               digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);
 
                /* disable input flow control */
                buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
@@ -1477,11 +1447,9 @@ static void digi_close(struct tty_struct *tty, struct usb_serial_port *port,
                /* shutdown any outstanding bulk writes */
                usb_kill_urb(port->write_urb);
        }
-       tty->closing = 0;
 exit:
        spin_lock_irq(&priv->dp_port_lock);
        priv->dp_write_urb_in_use = 0;
-       priv->dp_in_close = 0;
        wake_up_interruptible(&priv->dp_close_wait);
        spin_unlock_irq(&priv->dp_port_lock);
        mutex_unlock(&port->serial->disc_mutex);
@@ -1560,7 +1528,6 @@ static int digi_startup(struct usb_serial *serial)
                priv->dp_throttled = 0;
                priv->dp_throttle_restart = 0;
                init_waitqueue_head(&priv->dp_flush_wait);
-               priv->dp_in_close = 0;
                init_waitqueue_head(&priv->dp_close_wait);
                INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock);
                priv->dp_port = serial->port[i];
index c709ec474a80b8540e91d5ae6e25fde2690f6b09..2b141ccb0cd958ca56d51c476075dc621e0a5a4a 100644 (file)
@@ -81,8 +81,7 @@ static int debug;
 /* function prototypes for an empeg-car player */
 static int  empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
                                                struct file *filp);
-static void empeg_close(struct tty_struct *tty, struct usb_serial_port *port,
-                                               struct file *filp);
+static void empeg_close(struct usb_serial_port *port);
 static int  empeg_write(struct tty_struct *tty, struct usb_serial_port *port,
                                                const unsigned char *buf,
                                                int count);
@@ -181,8 +180,7 @@ static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
 }
 
 
-static void empeg_close(struct tty_struct *tty, struct usb_serial_port *port,
-                               struct file *filp)
+static void empeg_close(struct usb_serial_port *port)
 {
        dbg("%s - port %d", __func__, port->number);
 
index d9fcdaedf389d9c670b57847004939c44a25dc32..683304d60615a334554c3b6a0328de5d96879df5 100644 (file)
@@ -89,6 +89,7 @@ struct ftdi_private {
        int force_rtscts;       /* if non-zero, force RTS-CTS to always
                                   be enabled */
 
+       unsigned int latency;           /* latency setting in use */
        spinlock_t tx_lock;     /* spinlock for transmit state */
        unsigned long tx_bytes;
        unsigned long tx_outstanding_bytes;
@@ -719,8 +720,8 @@ static int  ftdi_sio_port_probe(struct usb_serial_port *port);
 static int  ftdi_sio_port_remove(struct usb_serial_port *port);
 static int  ftdi_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
-static void ftdi_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp);
+static void ftdi_close(struct usb_serial_port *port);
+static void ftdi_dtr_rts(struct usb_serial_port *port, int on);
 static int  ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
                        const unsigned char *buf, int count);
 static int  ftdi_write_room(struct tty_struct *tty);
@@ -758,6 +759,7 @@ static struct usb_serial_driver ftdi_sio_device = {
        .port_remove =          ftdi_sio_port_remove,
        .open =                 ftdi_open,
        .close =                ftdi_close,
+       .dtr_rts =              ftdi_dtr_rts,
        .throttle =             ftdi_throttle,
        .unthrottle =           ftdi_unthrottle,
        .write =                ftdi_write,
@@ -1037,7 +1039,54 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
        return rv;
 }
 
+static int write_latency_timer(struct usb_serial_port *port)
+{
+       struct ftdi_private *priv = usb_get_serial_port_data(port);
+       struct usb_device *udev = port->serial->dev;
+       char buf[1];
+       int rv = 0;
+       int l = priv->latency;
+
+       if (priv->flags & ASYNC_LOW_LATENCY)
+               l = 1;
+
+       dbg("%s: setting latency timer = %i", __func__, l);
+
+       rv = usb_control_msg(udev,
+                            usb_sndctrlpipe(udev, 0),
+                            FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
+                            FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
+                            l, priv->interface,
+                            buf, 0, WDR_TIMEOUT);
+
+       if (rv < 0)
+               dev_err(&port->dev, "Unable to write latency timer: %i\n", rv);
+       return rv;
+}
+
+static int read_latency_timer(struct usb_serial_port *port)
+{
+       struct ftdi_private *priv = usb_get_serial_port_data(port);
+       struct usb_device *udev = port->serial->dev;
+       unsigned short latency = 0;
+       int rv = 0;
+
 
+       dbg("%s", __func__);
+
+       rv = usb_control_msg(udev,
+                            usb_rcvctrlpipe(udev, 0),
+                            FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
+                            FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
+                            0, priv->interface,
+                            (char *) &latency, 1, WDR_TIMEOUT);
+
+       if (rv < 0) {
+               dev_err(&port->dev, "Unable to read latency timer: %i\n", rv);
+               return -EIO;
+       }
+       return latency;
+}
 
 static int get_serial_info(struct usb_serial_port *port,
                                struct serial_struct __user *retinfo)
@@ -1097,6 +1146,7 @@ static int set_serial_info(struct tty_struct *tty,
        priv->custom_divisor = new_serial.custom_divisor;
 
        tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+       write_latency_timer(port);
 
 check_and_exit:
        if ((old_priv.flags & ASYNC_SPD_MASK) !=
@@ -1192,27 +1242,13 @@ static ssize_t show_latency_timer(struct device *dev,
 {
        struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       struct usb_device *udev = port->serial->dev;
-       unsigned short latency = 0;
-       int rv = 0;
-
-
-       dbg("%s", __func__);
-
-       rv = usb_control_msg(udev,
-                            usb_rcvctrlpipe(udev, 0),
-                            FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
-                            FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
-                            0, priv->interface,
-                            (char *) &latency, 1, WDR_TIMEOUT);
-
-       if (rv < 0) {
-               dev_err(dev, "Unable to read latency timer: %i\n", rv);
-               return -EIO;
-       }
-       return sprintf(buf, "%i\n", latency);
+       if (priv->flags & ASYNC_LOW_LATENCY)
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "%i\n", priv->latency);
 }
 
+
 /* Write a new value of the latency timer, in units of milliseconds. */
 static ssize_t store_latency_timer(struct device *dev,
                        struct device_attribute *attr, const char *valbuf,
@@ -1220,25 +1256,13 @@ static ssize_t store_latency_timer(struct device *dev,
 {
        struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       struct usb_device *udev = port->serial->dev;
-       char buf[1];
        int v = simple_strtoul(valbuf, NULL, 10);
        int rv = 0;
 
-       dbg("%s: setting latency timer = %i", __func__, v);
-
-       rv = usb_control_msg(udev,
-                            usb_sndctrlpipe(udev, 0),
-                            FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
-                            FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
-                            v, priv->interface,
-                            buf, 0, WDR_TIMEOUT);
-
-       if (rv < 0) {
-               dev_err(dev, "Unable to write latency timer: %i\n", rv);
+       priv->latency = v;
+       rv = write_latency_timer(port);
+       if (rv < 0)
                return -EIO;
-       }
-
        return count;
 }
 
@@ -1392,6 +1416,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
        usb_set_serial_port_data(port, priv);
 
        ftdi_determine_type(port);
+       read_latency_timer(port);
        create_sysfs_attrs(port);
        return 0;
 }
@@ -1514,6 +1539,8 @@ static int ftdi_open(struct tty_struct *tty,
        if (tty)
                tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
+       write_latency_timer(port);
+
        /* No error checking for this (will get errors later anyway) */
        /* See ftdi_sio.h for description of what is reset */
        usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
@@ -1529,11 +1556,6 @@ static int ftdi_open(struct tty_struct *tty,
        if (tty)
                ftdi_set_termios(tty, port, tty->termios);
 
-       /* FIXME: Flow control might be enabled, so it should be checked -
-          we have no control of defaults! */
-       /* Turn on RTS and DTR since we are not flow controlling by default */
-       set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
-
        /* Not throttled */
        spin_lock_irqsave(&priv->rx_lock, flags);
        priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
@@ -1558,6 +1580,30 @@ static int ftdi_open(struct tty_struct *tty,
 } /* ftdi_open */
 
 
+static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
+{
+       struct ftdi_private *priv = usb_get_serial_port_data(port);
+       char buf[1];
+
+       mutex_lock(&port->serial->disc_mutex);
+       if (!port->serial->disconnected) {
+               /* Disable flow control */
+               if (!on && usb_control_msg(port->serial->dev,
+                           usb_sndctrlpipe(port->serial->dev, 0),
+                           FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+                           FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+                           0, priv->interface, buf, 0,
+                           WDR_TIMEOUT) < 0) {
+                           dev_err(&port->dev, "error from flowcontrol urb\n");
+               }
+               /* drop RTS and DTR */
+               if (on)
+                       set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+               else
+                       clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+       }
+       mutex_unlock(&port->serial->disc_mutex);
+}
 
 /*
  * usbserial:__serial_close  only calls ftdi_close if the point is open
@@ -1567,31 +1613,12 @@ static int ftdi_open(struct tty_struct *tty,
  *
  */
 
-static void ftdi_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void ftdi_close(struct usb_serial_port *port)
 { /* ftdi_close */
-       unsigned int c_cflag = tty->termios->c_cflag;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       char buf[1];
 
        dbg("%s", __func__);
 
-       mutex_lock(&port->serial->disc_mutex);
-       if (c_cflag & HUPCL && !port->serial->disconnected) {
-               /* Disable flow control */
-               if (usb_control_msg(port->serial->dev,
-                                   usb_sndctrlpipe(port->serial->dev, 0),
-                                   FTDI_SIO_SET_FLOW_CTRL_REQUEST,
-                                   FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-                                   0, priv->interface, buf, 0,
-                                   WDR_TIMEOUT) < 0) {
-                       dev_err(&port->dev, "error from flowcontrol urb\n");
-               }
-
-               /* drop RTS and DTR */
-               clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
-       } /* Note change no line if hupcl is off */
-       mutex_unlock(&port->serial->disc_mutex);
 
        /* cancel any scheduled reading */
        cancel_delayed_work_sync(&priv->rx_work);
index 586d30ff450b2eb9cc8346bd26ea3697056661ac..ee25a3fe3b09c317b0ecbb86f8dde60301bbc9b9 100644 (file)
@@ -993,8 +993,7 @@ static int garmin_open(struct tty_struct *tty,
 }
 
 
-static void garmin_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void garmin_close(struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
        struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
index 4cec9906ccf394ef312f07d152bbc64785f2cce0..be82ea956720184d545a0c43bce6f684c032fb7e 100644 (file)
@@ -184,8 +184,7 @@ int usb_serial_generic_resume(struct usb_serial *serial)
 }
 EXPORT_SYMBOL_GPL(usb_serial_generic_resume);
 
-void usb_serial_generic_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+void usb_serial_generic_close(struct usb_serial_port *port)
 {
        dbg("%s - port %d", __func__, port->number);
        generic_cleanup(port);
index fb4a73d090f6b9137daa847301a37545c48edc9b..53ef5996e33de377b6290c84e4183f2669ef646e 100644 (file)
@@ -207,8 +207,7 @@ static void edge_bulk_out_cmd_callback(struct urb *urb);
 /* function prototypes for the usbserial callbacks */
 static int edge_open(struct tty_struct *tty, struct usb_serial_port *port,
                                        struct file *filp);
-static void edge_close(struct tty_struct *tty, struct usb_serial_port *port,
-                                       struct file *filp);
+static void edge_close(struct usb_serial_port *port);
 static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
                                        const unsigned char *buf, int count);
 static int edge_write_room(struct tty_struct *tty);
@@ -965,7 +964,7 @@ static int edge_open(struct tty_struct *tty,
 
        if (!edge_port->txfifo.fifo) {
                dbg("%s - no memory", __func__);
-               edge_close(tty, port, filp);
+               edge_close(port);
                return -ENOMEM;
        }
 
@@ -975,7 +974,7 @@ static int edge_open(struct tty_struct *tty,
 
        if (!edge_port->write_urb) {
                dbg("%s - no memory", __func__);
-               edge_close(tty, port, filp);
+               edge_close(port);
                return -ENOMEM;
        }
 
@@ -1099,8 +1098,7 @@ static void block_until_tx_empty(struct edgeport_port *edge_port)
  * edge_close
  *     this function is called by the tty driver when a port is closed
  *****************************************************************************/
-static void edge_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void edge_close(struct usb_serial_port *port)
 {
        struct edgeport_serial *edge_serial;
        struct edgeport_port *edge_port;
index 513b25e044c166749f062843d246350bd2ea8ea3..eabf20eeb370ee4ce578c831b36003a7837d2bd9 100644 (file)
@@ -2009,8 +2009,7 @@ release_es_lock:
        return status;
 }
 
-static void edge_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void edge_close(struct usb_serial_port *port)
 {
        struct edgeport_serial *edge_serial;
        struct edgeport_port *edge_port;
index cd62825a9ac325e520d6cf0ba93f6e7cab763d66..c610a99fa47741c51d2b9312150f9ffc05868e23 100644 (file)
@@ -76,8 +76,7 @@ static int initial_wait;
 /* Function prototypes for an ipaq */
 static int  ipaq_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
-static void ipaq_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp);
+static void ipaq_close(struct usb_serial_port *port);
 static int  ipaq_calc_num_ports(struct usb_serial *serial);
 static int  ipaq_startup(struct usb_serial *serial);
 static void ipaq_shutdown(struct usb_serial *serial);
@@ -714,8 +713,7 @@ error:
 }
 
 
-static void ipaq_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void ipaq_close(struct usb_serial_port *port)
 {
        struct ipaq_private     *priv = usb_get_serial_port_data(port);
 
index da2a2b46644a5ddada6bd79abf71504df4148fb7..29ad038b9c8de2536a9373bb60b28f9ad7354044 100644 (file)
@@ -302,23 +302,17 @@ static int ipw_open(struct tty_struct *tty,
        return 0;
 }
 
-static void ipw_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void ipw_dtr_rts(struct usb_serial_port *port, int on)
 {
        struct usb_device *dev = port->serial->dev;
        int result;
 
-       if (tty_hung_up_p(filp)) {
-               dbg("%s: tty_hung_up_p ...", __func__);
-               return;
-       }
-
        /*--1: drop the dtr */
        dbg("%s:dropping dtr", __func__);
        result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                         IPW_SIO_SET_PIN,
                         USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
-                        IPW_PIN_CLRDTR,
+                        on ? IPW_PIN_SETDTR : IPW_PIN_CLRDTR,
                         0,
                         NULL,
                         0,
@@ -332,7 +326,7 @@ static void ipw_close(struct tty_struct *tty,
        result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                         IPW_SIO_SET_PIN, USB_TYPE_VENDOR |
                                        USB_RECIP_INTERFACE | USB_DIR_OUT,
-                        IPW_PIN_CLRRTS,
+                        on ? IPW_PIN_SETRTS : IPW_PIN_CLRRTS,
                         0,
                         NULL,
                         0,
@@ -340,7 +334,12 @@ static void ipw_close(struct tty_struct *tty,
        if (result < 0)
                dev_err(&port->dev,
                                "dropping rts failed (error = %d)\n", result);
+}
 
+static void ipw_close(struct usb_serial_port *port)
+{
+       struct usb_device *dev = port->serial->dev;
+       int result;
 
        /*--3: purge */
        dbg("%s:sending purge", __func__);
@@ -461,6 +460,7 @@ static struct usb_serial_driver ipw_device = {
        .num_ports =            1,
        .open =                 ipw_open,
        .close =                ipw_close,
+       .dtr_rts =              ipw_dtr_rts,
        .port_probe =           ipw_probe,
        .port_remove =          ipw_disconnect,
        .write =                ipw_write,
index 4e2cda93da596f7d5b98db2ae9a60b001418b392..66009b6b763a29a511551a9600d50802de63d3c9 100644 (file)
@@ -88,8 +88,7 @@ static int xbof = -1;
 static int  ir_startup (struct usb_serial *serial);
 static int  ir_open(struct tty_struct *tty, struct usb_serial_port *port,
                                        struct file *filep);
-static void ir_close(struct tty_struct *tty, struct usb_serial_port *port,
-                                       struct file *filep);
+static void ir_close(struct usb_serial_port *port);
 static int  ir_write(struct tty_struct *tty, struct usb_serial_port *port,
                                        const unsigned char *buf, int count);
 static void ir_write_bulk_callback (struct urb *urb);
@@ -346,8 +345,7 @@ static int ir_open(struct tty_struct *tty,
        return result;
 }
 
-static void ir_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file * filp)
+static void ir_close(struct usb_serial_port *port)
 {
        dbg("%s - port %d", __func__, port->number);
 
index 4473d442b2aa45357f7bfcea14aac39445de87da..76a3cc327bb9c2d0dbfdfa0a0e0df55015e15036 100644 (file)
@@ -40,7 +40,7 @@ static int debug;
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.5"
+#define DRIVER_VERSION "v0.10"
 #define DRIVER_DESC "Infinity USB Unlimited Phoenix driver"
 
 static struct usb_device_id id_table[] = {
@@ -70,7 +70,6 @@ static void read_rxcmd_callback(struct urb *urb);
 struct iuu_private {
        spinlock_t lock;        /* store irq state */
        wait_queue_head_t delta_msr_wait;
-       u8 line_control;
        u8 line_status;
        u8 termios_initialized;
        int tiostatus;          /* store IUART SIGNAL for tiocmget call */
@@ -651,32 +650,33 @@ static int iuu_bulk_write(struct usb_serial_port *port)
        unsigned long flags;
        int result;
        int i;
+       int buf_len;
        char *buf_ptr = port->write_urb->transfer_buffer;
        dbg("%s - enter", __func__);
 
+       spin_lock_irqsave(&priv->lock, flags);
        *buf_ptr++ = IUU_UART_ESC;
        *buf_ptr++ = IUU_UART_TX;
        *buf_ptr++ = priv->writelen;
 
-       memcpy(buf_ptr, priv->writebuf,
-              priv->writelen);
+       memcpy(buf_ptr, priv->writebuf, priv->writelen);
+       buf_len = priv->writelen;
+       priv->writelen = 0;
+       spin_unlock_irqrestore(&priv->lock, flags);
        if (debug == 1) {
-               for (i = 0; i < priv->writelen; i++)
+               for (i = 0; i < buf_len; i++)
                        sprintf(priv->dbgbuf + i*2 ,
                                "%02X", priv->writebuf[i]);
-               priv->dbgbuf[priv->writelen+i*2] = 0;
+               priv->dbgbuf[buf_len+i*2] = 0;
                dbg("%s - writing %i chars : %s", __func__,
-                   priv->writelen, priv->dbgbuf);
+                   buf_len, priv->dbgbuf);
        }
        usb_fill_bulk_urb(port->write_urb, port->serial->dev,
                          usb_sndbulkpipe(port->serial->dev,
                                          port->bulk_out_endpointAddress),
-                         port->write_urb->transfer_buffer, priv->writelen + 3,
+                         port->write_urb->transfer_buffer, buf_len + 3,
                          iuu_rxcmd, port);
        result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-       spin_lock_irqsave(&priv->lock, flags);
-       priv->writelen = 0;
-       spin_unlock_irqrestore(&priv->lock, flags);
        usb_serial_port_softint(port);
        return result;
 }
@@ -770,14 +770,10 @@ static int iuu_uart_write(struct tty_struct *tty, struct usb_serial_port *port,
                return -ENOMEM;
 
        spin_lock_irqsave(&priv->lock, flags);
-       if (priv->writelen > 0) {
-               /* buffer already filled but not commited */
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return 0;
-       }
+
        /* fill the buffer */
-       memcpy(priv->writebuf, buf, count);
-       priv->writelen = count;
+       memcpy(priv->writebuf + priv->writelen, buf, count);
+       priv->writelen += count;
        spin_unlock_irqrestore(&priv->lock, flags);
 
        return count;
@@ -819,7 +815,7 @@ static int iuu_uart_on(struct usb_serial_port *port)
        buf[0] = IUU_UART_ENABLE;
        buf[1] = (u8) ((IUU_BAUD_9600 >> 8) & 0x00FF);
        buf[2] = (u8) (0x00FF & IUU_BAUD_9600);
-       buf[3] = (u8) (0x0F0 & IUU_TWO_STOP_BITS) | (0x07 & IUU_PARITY_EVEN);
+       buf[3] = (u8) (0x0F0 & IUU_ONE_STOP_BIT) | (0x07 & IUU_PARITY_EVEN);
 
        status = bulk_immediate(port, buf, 4);
        if (status != IUU_OPERATION_OK) {
@@ -946,19 +942,59 @@ static int iuu_uart_baud(struct usb_serial_port *port, u32 baud,
        return status;
 }
 
-static int set_control_lines(struct usb_device *dev, u8 value)
+static void iuu_set_termios(struct tty_struct *tty,
+               struct usb_serial_port *port, struct ktermios *old_termios)
 {
-       return 0;
+       const u32 supported_mask = CMSPAR|PARENB|PARODD;
+
+       unsigned int cflag = tty->termios->c_cflag;
+       int status;
+       u32 actual;
+       u32 parity;
+       int csize = CS7;
+       int baud = 9600;        /* Fixed for the moment */
+       u32 newval = cflag & supported_mask;
+
+       /* compute the parity parameter */
+       parity = 0;
+       if (cflag & CMSPAR) {   /* Using mark space */
+               if (cflag & PARODD)
+                       parity |= IUU_PARITY_SPACE;
+               else
+                       parity |= IUU_PARITY_MARK;
+       } else if (!(cflag & PARENB)) {
+               parity |= IUU_PARITY_NONE;
+               csize = CS8;
+       } else if (cflag & PARODD)
+               parity |= IUU_PARITY_ODD;
+       else
+               parity |= IUU_PARITY_EVEN;
+
+       parity |= (cflag & CSTOPB ? IUU_TWO_STOP_BITS : IUU_ONE_STOP_BIT);
+
+       /* set it */
+       status = iuu_uart_baud(port,
+                       (clockmode == 2) ? 16457 : 9600 * boost / 100,
+                       &actual, parity);
+
+       /* set the termios value to the real one, so the user now what has
+        * changed. We support few fields so its easies to copy the old hw
+        * settings back over and then adjust them
+        */
+       if (old_termios)
+               tty_termios_copy_hw(tty->termios, old_termios);
+       if (status != 0)        /* Set failed - return old bits */
+               return;
+       /* Re-encode speed, parity and csize */
+       tty_encode_baud_rate(tty, baud, baud);
+       tty->termios->c_cflag &= ~(supported_mask|CSIZE);
+       tty->termios->c_cflag |= newval | csize;
 }
 
-static void iuu_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void iuu_close(struct usb_serial_port *port)
 {
        /* iuu_led (port,255,0,0,0); */
        struct usb_serial *serial;
-       struct iuu_private *priv = usb_get_serial_port_data(port);
-       unsigned long flags;
-       unsigned int c_cflag;
 
        serial = port->serial;
        if (!serial)
@@ -968,17 +1004,6 @@ static void iuu_close(struct tty_struct *tty,
 
        iuu_uart_off(port);
        if (serial->dev) {
-               if (tty) {
-                       c_cflag = tty->termios->c_cflag;
-                       if (c_cflag & HUPCL) {
-                               /* drop DTR and RTS */
-                               priv = usb_get_serial_port_data(port);
-                               spin_lock_irqsave(&priv->lock, flags);
-                               priv->line_control = 0;
-                               spin_unlock_irqrestore(&priv->lock, flags);
-                               set_control_lines(port->serial->dev, 0);
-                       }
-               }
                /* free writebuf */
                /* shutdown our urbs */
                dbg("%s - shutting down urbs", __func__);
@@ -1154,7 +1179,7 @@ static int iuu_open(struct tty_struct *tty,
        if (result) {
                dev_err(&port->dev, "%s - failed submitting read urb,"
                        " error %d\n", __func__, result);
-               iuu_close(tty, port, NULL);
+               iuu_close(port);
                return -EPROTO;
        } else {
                dbg("%s - rxcmd OK", __func__);
@@ -1175,6 +1200,7 @@ static struct usb_serial_driver iuu_device = {
        .read_bulk_callback = iuu_uart_read_callback,
        .tiocmget = iuu_tiocmget,
        .tiocmset = iuu_tiocmset,
+       .set_termios = iuu_set_termios,
        .attach = iuu_startup,
        .shutdown = iuu_shutdown,
 };
index 00daa8f7759a99946fc3a902dc1e46c9a2bf55af..f1195a98f316df62f0d465b144b32fc3f6f9da66 100644 (file)
@@ -1298,8 +1298,16 @@ static inline void stop_urb(struct urb *urb)
                usb_kill_urb(urb);
 }
 
-static void keyspan_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
+{
+       struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
+
+       p_priv->rts_state = on;
+       p_priv->dtr_state = on;
+       keyspan_send_setup(port, 0);
+}
+
+static void keyspan_close(struct usb_serial_port *port)
 {
        int                     i;
        struct usb_serial       *serial = port->serial;
@@ -1336,7 +1344,6 @@ static void keyspan_close(struct tty_struct *tty,
                        stop_urb(p_priv->out_urbs[i]);
                }
        }
-       tty_port_tty_set(&port->port, NULL);
 }
 
 /* download the firmware to a pre-renumeration device */
index 38b4582e073446ad6513b7ed11145ccc6a26e61c..0d4569b60768a736a1e180db3621aa9053f22e72 100644 (file)
@@ -38,9 +38,8 @@
 static int  keyspan_open               (struct tty_struct *tty,
                                         struct usb_serial_port *port,
                                         struct file *filp);
-static void keyspan_close              (struct tty_struct *tty,
-                                        struct usb_serial_port *port,
-                                        struct file *filp);
+static void keyspan_close              (struct usb_serial_port *port);
+static void keyspan_dtr_rts            (struct usb_serial_port *port, int on);
 static int  keyspan_startup            (struct usb_serial *serial);
 static void keyspan_shutdown           (struct usb_serial *serial);
 static int  keyspan_write_room         (struct tty_struct *tty);
@@ -562,6 +561,7 @@ static struct usb_serial_driver keyspan_1port_device = {
        .num_ports              = 1,
        .open                   = keyspan_open,
        .close                  = keyspan_close,
+       .dtr_rts                = keyspan_dtr_rts,
        .write                  = keyspan_write,
        .write_room             = keyspan_write_room,
        .set_termios            = keyspan_set_termios,
@@ -582,6 +582,7 @@ static struct usb_serial_driver keyspan_2port_device = {
        .num_ports              = 2,
        .open                   = keyspan_open,
        .close                  = keyspan_close,
+       .dtr_rts                = keyspan_dtr_rts,
        .write                  = keyspan_write,
        .write_room             = keyspan_write_room,
        .set_termios            = keyspan_set_termios,
@@ -602,6 +603,7 @@ static struct usb_serial_driver keyspan_4port_device = {
        .num_ports              = 4,
        .open                   = keyspan_open,
        .close                  = keyspan_close,
+       .dtr_rts                = keyspan_dtr_rts,
        .write                  = keyspan_write,
        .write_room             = keyspan_write_room,
        .set_termios            = keyspan_set_termios,
index bf1ae247da66133f64ee79d57f15ef6619f82aa2..ab769dbea1b3e6f66d4df15ce6166caca8a17a50 100644 (file)
@@ -651,6 +651,35 @@ static int keyspan_pda_chars_in_buffer(struct tty_struct *tty)
 }
 
 
+static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on)
+{
+       struct usb_serial *serial = port->serial;
+
+       if (serial->dev) {
+               if (on)
+                       keyspan_pda_set_modem_info(serial, (1<<7) | (1<< 2));
+               else
+                       keyspan_pda_set_modem_info(serial, 0);
+       }
+}
+
+static int keyspan_pda_carrier_raised(struct usb_serial_port *port)
+{
+       struct usb_serial *serial = port->serial;
+       unsigned char modembits;
+
+       /* If we can read the modem status and the DCD is low then
+          carrier is not raised yet */
+       if (keyspan_pda_get_modem_info(serial, &modembits) >= 0) {
+               if (!(modembits & (1>>6)))
+                       return 0;
+       }
+       /* Carrier raised, or we failed (eg disconnected) so
+          progress accordingly */
+       return 1;
+}
+
+
 static int keyspan_pda_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp)
 {
@@ -682,13 +711,6 @@ static int keyspan_pda_open(struct tty_struct *tty,
        priv->tx_room = room;
        priv->tx_throttled = room ? 0 : 1;
 
-       /* the normal serial device seems to always turn on DTR and RTS here,
-          so do the same */
-       if (tty && (tty->termios->c_cflag & CBAUD))
-               keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2));
-       else
-               keyspan_pda_set_modem_info(serial, 0);
-
        /*Start reading from the device*/
        port->interrupt_in_urb->dev = serial->dev;
        rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
@@ -700,19 +722,11 @@ static int keyspan_pda_open(struct tty_struct *tty,
 error:
        return rc;
 }
-
-
-static void keyspan_pda_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void keyspan_pda_close(struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
 
        if (serial->dev) {
-               /* the normal serial device seems to always shut
-                  off DTR and RTS now */
-               if (tty->termios->c_cflag & HUPCL)
-                       keyspan_pda_set_modem_info(serial, 0);
-
                /* shutdown our bulk reads and writes */
                usb_kill_urb(port->write_urb);
                usb_kill_urb(port->interrupt_in_urb);
@@ -839,6 +853,8 @@ static struct usb_serial_driver keyspan_pda_device = {
        .usb_driver =           &keyspan_pda_driver,
        .id_table =             id_table_std,
        .num_ports =            1,
+       .dtr_rts =              keyspan_pda_dtr_rts,
+       .carrier_raised =       keyspan_pda_carrier_raised,
        .open =                 keyspan_pda_open,
        .close =                keyspan_pda_close,
        .write =                keyspan_pda_write,
index fcd9082f3e7f05d93fedc3073e3f6a87c318a6a8..fa817c66b3e8c827bb6ce0837591f2406dd73f70 100644 (file)
@@ -76,8 +76,7 @@ static int  klsi_105_startup(struct usb_serial *serial);
 static void klsi_105_shutdown(struct usb_serial *serial);
 static int  klsi_105_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
-static void klsi_105_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp);
+static void klsi_105_close(struct usb_serial_port *port);
 static int  klsi_105_write(struct tty_struct *tty,
        struct usb_serial_port *port, const unsigned char *buf, int count);
 static void klsi_105_write_bulk_callback(struct urb *urb);
@@ -447,8 +446,7 @@ exit:
 } /* klsi_105_open */
 
 
-static void klsi_105_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void klsi_105_close(struct usb_serial_port *port)
 {
        struct klsi_105_private *priv = usb_get_serial_port_data(port);
        int rc;
index c148544953b37df33a00fc9873377a31168de993..6b570498287f3f5d62d337e6a347945101b638c3 100644 (file)
@@ -72,8 +72,7 @@ static int  kobil_startup(struct usb_serial *serial);
 static void kobil_shutdown(struct usb_serial *serial);
 static int  kobil_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
-static void kobil_close(struct tty_struct *tty, struct usb_serial_port *port,
-                       struct file *filp);
+static void kobil_close(struct usb_serial_port *port);
 static int  kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
                         const unsigned char *buf, int count);
 static int  kobil_write_room(struct tty_struct *tty);
@@ -209,7 +208,7 @@ static void kobil_shutdown(struct usb_serial *serial)
 
        for (i = 0; i < serial->num_ports; ++i) {
                while (serial->port[i]->port.count > 0)
-                       kobil_close(NULL, serial->port[i], NULL);
+                       kobil_close(serial->port[i]);
                kfree(usb_get_serial_port_data(serial->port[i]));
                usb_set_serial_port_data(serial->port[i], NULL);
        }
@@ -346,11 +345,11 @@ static int kobil_open(struct tty_struct *tty,
 }
 
 
-static void kobil_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void kobil_close(struct usb_serial_port *port)
 {
        dbg("%s - port %d", __func__, port->number);
 
+       /* FIXME: Add rts/dtr methods */
        if (port->write_urb) {
                usb_kill_urb(port->write_urb);
                usb_free_urb(port->write_urb);
index 82930a7d509327c2797ef474042e0a3d2a4106ac..873795548fc0a976a5bd129e3316933c9eda069b 100644 (file)
@@ -95,8 +95,8 @@ static int  mct_u232_startup(struct usb_serial *serial);
 static void mct_u232_shutdown(struct usb_serial *serial);
 static int  mct_u232_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
-static void mct_u232_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp);
+static void mct_u232_close(struct usb_serial_port *port);
+static void mct_u232_dtr_rts(struct usb_serial_port *port, int on);
 static void mct_u232_read_int_callback(struct urb *urb);
 static void mct_u232_set_termios(struct tty_struct *tty,
                        struct usb_serial_port *port, struct ktermios *old);
@@ -140,6 +140,7 @@ static struct usb_serial_driver mct_u232_device = {
        .num_ports =         1,
        .open =              mct_u232_open,
        .close =             mct_u232_close,
+       .dtr_rts =           mct_u232_dtr_rts,
        .throttle =          mct_u232_throttle,
        .unthrottle =        mct_u232_unthrottle,
        .read_int_callback = mct_u232_read_int_callback,
@@ -496,29 +497,29 @@ error:
        return retval;
 } /* mct_u232_open */
 
-
-static void mct_u232_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void mct_u232_dtr_rts(struct usb_serial_port *port, int on)
 {
-       unsigned int c_cflag;
        unsigned int control_state;
        struct mct_u232_private *priv = usb_get_serial_port_data(port);
-       dbg("%s port %d", __func__, port->number);
 
-       if (tty) {
-               c_cflag = tty->termios->c_cflag;
-               mutex_lock(&port->serial->disc_mutex);
-               if (c_cflag & HUPCL && !port->serial->disconnected) {
-                       /* drop DTR and RTS */
-                       spin_lock_irq(&priv->lock);
+       mutex_lock(&port->serial->disc_mutex);
+       if (!port->serial->disconnected) {
+               /* drop DTR and RTS */
+               spin_lock_irq(&priv->lock);
+               if (on)
+                       priv->control_state |= TIOCM_DTR | TIOCM_RTS;
+               else
                        priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
-                       control_state = priv->control_state;
-                       spin_unlock_irq(&priv->lock);
-                       mct_u232_set_modem_ctrl(port->serial, control_state);
-               }
-               mutex_unlock(&port->serial->disc_mutex);
+               control_state = priv->control_state;
+               spin_unlock_irq(&priv->lock);
+               mct_u232_set_modem_ctrl(port->serial, control_state);
        }
+       mutex_unlock(&port->serial->disc_mutex);
+}
 
+static void mct_u232_close(struct usb_serial_port *port)
+{
+       dbg("%s port %d", __func__, port->number);
 
        if (port->serial->dev) {
                /* shutdown our urbs */
index 24e3b5d4b4d49f088a9891718bc36c815c4a409c..9e1a013ee7f679177e7b588aabbb2b6534d4cda3 100644 (file)
@@ -533,8 +533,7 @@ static int mos7720_chars_in_buffer(struct tty_struct *tty)
        return chars;
 }
 
-static void mos7720_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void mos7720_close(struct usb_serial_port *port)
 {
        struct usb_serial *serial;
        struct moschip_port *mos7720_port;
index 84fb1dcd30dc3eacdf186c3666375775ff9b1fad..10b78a37214f6c337b1ac1bb3cb93219a9bbd3ba 100644 (file)
@@ -1135,54 +1135,12 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty)
 
 }
 
-/************************************************************************
- *
- * mos7840_block_until_tx_empty
- *
- *     This function will block the close until one of the following:
- *             1. TX count are 0
- *             2. The mos7840 has stopped
- *             3. A timeout of 3 seconds without activity has expired
- *
- ************************************************************************/
-static void mos7840_block_until_tx_empty(struct tty_struct *tty,
-                               struct moschip_port *mos7840_port)
-{
-       int timeout = HZ / 10;
-       int wait = 30;
-       int count;
-
-       while (1) {
-
-               count = mos7840_chars_in_buffer(tty);
-
-               /* Check for Buffer status */
-               if (count <= 0)
-                       return;
-
-               /* Block the thread for a while */
-               interruptible_sleep_on_timeout(&mos7840_port->wait_chase,
-                                              timeout);
-
-               /* No activity.. count down section */
-               wait--;
-               if (wait == 0) {
-                       dbg("%s - TIMEOUT", __func__);
-                       return;
-               } else {
-                       /* Reset timeout value back to seconds */
-                       wait = 30;
-               }
-       }
-}
-
 /*****************************************************************************
  * mos7840_close
  *     this function is called by the tty driver when a port is closed
  *****************************************************************************/
 
-static void mos7840_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void mos7840_close(struct usb_serial_port *port)
 {
        struct usb_serial *serial;
        struct moschip_port *mos7840_port;
@@ -1223,10 +1181,6 @@ static void mos7840_close(struct tty_struct *tty,
                }
        }
 
-       if (serial->dev)
-               /* flush and block until tx is empty */
-               mos7840_block_until_tx_empty(tty, mos7840_port);
-
        /* While closing port, shutdown all bulk read, write  *
         * and interrupt read if they exists                  */
        if (serial->dev) {
index bcdcbb822705fd952863dcd5d041abef4d8daad3..f5f3751a888ced2547abf459d63e99a6cafe3a7e 100644 (file)
@@ -98,8 +98,7 @@ static int navman_open(struct tty_struct *tty,
        return result;
 }
 
-static void navman_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void navman_close(struct usb_serial_port *port)
 {
        dbg("%s - port %d", __func__, port->number);
 
index df6539712726b93b8c007ecea018a5ed9ea4cb50..1104617334f50d9ff4e9afbbe3d3b21934f92cc3 100644 (file)
@@ -66,8 +66,7 @@ static int debug;
 /* function prototypes */
 static int  omninet_open(struct tty_struct *tty, struct usb_serial_port *port,
                                                        struct file *filp);
-static void omninet_close(struct tty_struct *tty, struct usb_serial_port *port,
-                                                       struct file *filp);
+static void omninet_close(struct usb_serial_port *port);
 static void omninet_read_bulk_callback(struct urb *urb);
 static void omninet_write_bulk_callback(struct urb *urb);
 static int  omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
@@ -189,8 +188,7 @@ static int omninet_open(struct tty_struct *tty,
        return result;
 }
 
-static void omninet_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void omninet_close(struct usb_serial_port *port)
 {
        dbg("%s - port %d", __func__, port->number);
        usb_kill_urb(port->read_urb);
index b500ad10b7589185087bbcb64cc0e4ba97fbfd3b..c20480aa975558c9fdac755fe0323991e6c1b4f6 100644 (file)
@@ -173,8 +173,7 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port,
        return result;
 }
 
-static void opticon_close(struct tty_struct *tty, struct usb_serial_port *port,
-                         struct file *filp)
+static void opticon_close(struct usb_serial_port *port)
 {
        struct opticon_private *priv = usb_get_serial_data(port->serial);
 
index 7817b82889ca5e56eeb0c63a01c9351cf1a02612..a16d69fadba1cd9fa7088b9baa3a598b6402c2d9 100644 (file)
@@ -45,8 +45,9 @@
 /* Function prototypes */
 static int  option_open(struct tty_struct *tty, struct usb_serial_port *port,
                                                        struct file *filp);
-static void option_close(struct tty_struct *tty, struct usb_serial_port *port,
-                                                       struct file *filp);
+static void option_close(struct usb_serial_port *port);
+static void option_dtr_rts(struct usb_serial_port *port, int on);
+
 static int  option_startup(struct usb_serial *serial);
 static void option_shutdown(struct usb_serial *serial);
 static int  option_write_room(struct tty_struct *tty);
@@ -61,7 +62,7 @@ static void option_set_termios(struct tty_struct *tty,
 static int  option_tiocmget(struct tty_struct *tty, struct file *file);
 static int  option_tiocmset(struct tty_struct *tty, struct file *file,
                                unsigned int set, unsigned int clear);
-static int  option_send_setup(struct tty_struct *tty, struct usb_serial_port *port);
+static int  option_send_setup(struct usb_serial_port *port);
 static int  option_suspend(struct usb_serial *serial, pm_message_t message);
 static int  option_resume(struct usb_serial *serial);
 
@@ -551,6 +552,7 @@ static struct usb_serial_driver option_1port_device = {
        .num_ports         = 1,
        .open              = option_open,
        .close             = option_close,
+       .dtr_rts           = option_dtr_rts,
        .write             = option_write,
        .write_room        = option_write_room,
        .chars_in_buffer   = option_chars_in_buffer,
@@ -630,7 +632,7 @@ static void option_set_termios(struct tty_struct *tty,
        dbg("%s", __func__);
        /* Doesn't support option setting */
        tty_termios_copy_hw(tty->termios, old_termios);
-       option_send_setup(tty, port);
+       option_send_setup(port);
 }
 
 static int option_tiocmget(struct tty_struct *tty, struct file *file)
@@ -669,7 +671,7 @@ static int option_tiocmset(struct tty_struct *tty, struct file *file,
                portdata->rts_state = 0;
        if (clear & TIOCM_DTR)
                portdata->dtr_state = 0;
-       return option_send_setup(tty, port);
+       return option_send_setup(port);
 }
 
 /* Write */
@@ -897,10 +899,6 @@ static int option_open(struct tty_struct *tty,
 
        dbg("%s", __func__);
 
-       /* Set some sane defaults */
-       portdata->rts_state = 1;
-       portdata->dtr_state = 1;
-
        /* Reset low level data toggle and start reading from endpoints */
        for (i = 0; i < N_IN_URB; i++) {
                urb = portdata->in_urbs[i];
@@ -936,37 +934,43 @@ static int option_open(struct tty_struct *tty,
                                usb_pipeout(urb->pipe), 0); */
        }
 
-       option_send_setup(tty, port);
+       option_send_setup(port);
 
        return 0;
 }
 
-static void option_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void option_dtr_rts(struct usb_serial_port *port, int on)
 {
-       int i;
        struct usb_serial *serial = port->serial;
        struct option_port_private *portdata;
 
        dbg("%s", __func__);
        portdata = usb_get_serial_port_data(port);
+       mutex_lock(&serial->disc_mutex);
+       portdata->rts_state = on;
+       portdata->dtr_state = on;
+       if (serial->dev)
+               option_send_setup(port);
+       mutex_unlock(&serial->disc_mutex);
+}
 
-       portdata->rts_state = 0;
-       portdata->dtr_state = 0;
 
-       if (serial->dev) {
-               mutex_lock(&serial->disc_mutex);
-               if (!serial->disconnected)
-                       option_send_setup(tty, port);
-               mutex_unlock(&serial->disc_mutex);
+static void option_close(struct usb_serial_port *port)
+{
+       int i;
+       struct usb_serial *serial = port->serial;
+       struct option_port_private *portdata;
+
+       dbg("%s", __func__);
+       portdata = usb_get_serial_port_data(port);
 
+       if (serial->dev) {
                /* Stop reading/writing urbs */
                for (i = 0; i < N_IN_URB; i++)
                        usb_kill_urb(portdata->in_urbs[i]);
                for (i = 0; i < N_OUT_URB; i++)
                        usb_kill_urb(portdata->out_urbs[i]);
        }
-       tty_port_tty_set(&port->port, NULL);
 }
 
 /* Helper functions used by option_setup_urbs */
@@ -1032,28 +1036,24 @@ static void option_setup_urbs(struct usb_serial *serial)
  * This is exactly the same as SET_CONTROL_LINE_STATE from the PSTN
  * CDC.
 */
-static int option_send_setup(struct tty_struct *tty,
-                                               struct usb_serial_port *port)
+static int option_send_setup(struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
        struct option_port_private *portdata;
        int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
+       int val = 0;
        dbg("%s", __func__);
 
        portdata = usb_get_serial_port_data(port);
 
-       if (tty) {
-               int val = 0;
-               if (portdata->dtr_state)
-                       val |= 0x01;
-               if (portdata->rts_state)
-                       val |= 0x02;
+       if (portdata->dtr_state)
+               val |= 0x01;
+       if (portdata->rts_state)
+               val |= 0x02;
 
-               return usb_control_msg(serial->dev,
-                       usb_rcvctrlpipe(serial->dev, 0),
-                       0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT);
-       }
-       return 0;
+       return usb_control_msg(serial->dev,
+               usb_rcvctrlpipe(serial->dev, 0),
+               0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT);
 }
 
 static int option_startup(struct usb_serial *serial)
index ba551f00f16ff1ec30fbcd90422f1e1112e8c00a..7de54781fe614e96d32ee69327822f02416c3801 100644 (file)
@@ -143,8 +143,7 @@ struct oti6858_control_pkt {
 /* function prototypes */
 static int oti6858_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
-static void oti6858_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp);
+static void oti6858_close(struct usb_serial_port *port);
 static void oti6858_set_termios(struct tty_struct *tty,
                        struct usb_serial_port *port, struct ktermios *old);
 static int oti6858_ioctl(struct tty_struct *tty, struct file *file,
@@ -622,67 +621,30 @@ static int oti6858_open(struct tty_struct *tty,
        if (result != 0) {
                dev_err(&port->dev, "%s(): usb_submit_urb() failed"
                               " with error %d\n", __func__, result);
-               oti6858_close(tty, port, NULL);
+               oti6858_close(port);
                return -EPROTO;
        }
 
        /* setup termios */
        if (tty)
                oti6858_set_termios(tty, port, &tmp_termios);
-
+       port->port.drain_delay = 256;   /* FIXME: check the FIFO length */
        return 0;
 }
 
-static void oti6858_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void oti6858_close(struct usb_serial_port *port)
 {
        struct oti6858_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
-       long timeout;
-       wait_queue_t wait;
 
        dbg("%s(port = %d)", __func__, port->number);
 
-       /* wait for data to drain from the buffer */
        spin_lock_irqsave(&priv->lock, flags);
-       timeout = 30 * HZ;      /* PL2303_CLOSING_WAIT */
-       init_waitqueue_entry(&wait, current);
-       add_wait_queue(&tty->write_wait, &wait);
-       dbg("%s(): entering wait loop", __func__);
-       for (;;) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (oti6858_buf_data_avail(priv->buf) == 0
-               || timeout == 0 || signal_pending(current)
-               || port->serial->disconnected)
-                       break;
-               spin_unlock_irqrestore(&priv->lock, flags);
-               timeout = schedule_timeout(timeout);
-               spin_lock_irqsave(&priv->lock, flags);
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&tty->write_wait, &wait);
-       dbg("%s(): after wait loop", __func__);
-
        /* clear out any remaining data in the buffer */
        oti6858_buf_clear(priv->buf);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       /* wait for characters to drain from the device */
-       /* (this is long enough for the entire 256 byte */
-       /* pl2303 hardware buffer to drain with no flow */
-       /* control for data rates of 1200 bps or more, */
-       /* for lower rates we should really know how much */
-       /* data is in the buffer to compute a delay */
-       /* that is not unnecessarily long) */
-       /* FIXME
-       bps = tty_get_baud_rate(tty);
-       if (bps > 1200)
-               timeout = max((HZ*2560)/bps,HZ/10);
-       else
-       */
-               timeout = 2*HZ;
-       schedule_timeout_interruptible(timeout);
-       dbg("%s(): after schedule_timeout_interruptible()", __func__);
+       dbg("%s(): after buf_clear()", __func__);
 
        /* cancel scheduled setup */
        cancel_delayed_work(&priv->delayed_setup_work);
@@ -694,15 +656,6 @@ static void oti6858_close(struct tty_struct *tty,
        usb_kill_urb(port->write_urb);
        usb_kill_urb(port->read_urb);
        usb_kill_urb(port->interrupt_in_urb);
-
-       /*
-       if (tty && (tty->termios->c_cflag) & HUPCL) {
-               // drop DTR and RTS
-               spin_lock_irqsave(&priv->lock, flags);
-               priv->pending_setup.control &= ~CONTROL_MASK;
-               spin_unlock_irqrestore(&priv->lock, flags);
-       }
-       */
 }
 
 static int oti6858_tiocmset(struct tty_struct *tty, struct file *file,
index 751a533a4347e7324725afb8948b75fcb2437bbd..e02dc3d643c7ae1279f467b21584e2899a82dfb7 100644 (file)
@@ -652,69 +652,41 @@ static void pl2303_set_termios(struct tty_struct *tty,
        kfree(buf);
 }
 
-static void pl2303_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
+{
+       struct pl2303_private *priv = usb_get_serial_port_data(port);
+       unsigned long flags;
+       u8 control;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       /* Change DTR and RTS */
+       if (on)
+               priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
+       else
+               priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
+       control = priv->line_control;
+       spin_unlock_irqrestore(&priv->lock, flags);
+       set_control_lines(port->serial->dev, control);
+}
+
+static void pl2303_close(struct usb_serial_port *port)
 {
        struct pl2303_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
-       unsigned int c_cflag;
-       int bps;
-       long timeout;
-       wait_queue_t wait;
 
        dbg("%s - port %d", __func__, port->number);
 
-       /* wait for data to drain from the buffer */
        spin_lock_irqsave(&priv->lock, flags);
-       timeout = PL2303_CLOSING_WAIT;
-       init_waitqueue_entry(&wait, current);
-       add_wait_queue(&tty->write_wait, &wait);
-       for (;;) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (pl2303_buf_data_avail(priv->buf) == 0 ||
-                   timeout == 0 || signal_pending(current) ||
-                   port->serial->disconnected)
-                       break;
-               spin_unlock_irqrestore(&priv->lock, flags);
-               timeout = schedule_timeout(timeout);
-               spin_lock_irqsave(&priv->lock, flags);
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&tty->write_wait, &wait);
        /* clear out any remaining data in the buffer */
        pl2303_buf_clear(priv->buf);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       /* wait for characters to drain from the device */
-       /* (this is long enough for the entire 256 byte */
-       /* pl2303 hardware buffer to drain with no flow */
-       /* control for data rates of 1200 bps or more, */
-       /* for lower rates we should really know how much */
-       /* data is in the buffer to compute a delay */
-       /* that is not unnecessarily long) */
-       bps = tty_get_baud_rate(tty);
-       if (bps > 1200)
-               timeout = max((HZ*2560)/bps, HZ/10);
-       else
-               timeout = 2*HZ;
-       schedule_timeout_interruptible(timeout);
-
        /* shutdown our urbs */
        dbg("%s - shutting down urbs", __func__);
        usb_kill_urb(port->write_urb);
        usb_kill_urb(port->read_urb);
        usb_kill_urb(port->interrupt_in_urb);
 
-       if (tty) {
-               c_cflag = tty->termios->c_cflag;
-               if (c_cflag & HUPCL) {
-                       /* drop DTR and RTS */
-                       spin_lock_irqsave(&priv->lock, flags);
-                       priv->line_control = 0;
-                       spin_unlock_irqrestore(&priv->lock, flags);
-                       set_control_lines(port->serial->dev, 0);
-               }
-       }
 }
 
 static int pl2303_open(struct tty_struct *tty,
@@ -748,7 +720,7 @@ static int pl2303_open(struct tty_struct *tty,
        if (result) {
                dev_err(&port->dev, "%s - failed submitting read urb,"
                        " error %d\n", __func__, result);
-               pl2303_close(tty, port, NULL);
+               pl2303_close(port);
                return -EPROTO;
        }
 
@@ -758,9 +730,10 @@ static int pl2303_open(struct tty_struct *tty,
        if (result) {
                dev_err(&port->dev, "%s - failed submitting interrupt urb,"
                        " error %d\n", __func__, result);
-               pl2303_close(tty, port, NULL);
+               pl2303_close(port);
                return -EPROTO;
        }
+       port->port.drain_delay = 256;
        return 0;
 }
 
@@ -821,6 +794,14 @@ static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
        return result;
 }
 
+static int pl2303_carrier_raised(struct usb_serial_port *port)
+{
+       struct pl2303_private *priv = usb_get_serial_port_data(port);
+       if (priv->line_status & UART_DCD)
+               return 1;
+       return 0;
+}
+
 static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
 {
        struct pl2303_private *priv = usb_get_serial_port_data(port);
@@ -1125,6 +1106,8 @@ static struct usb_serial_driver pl2303_device = {
        .num_ports =            1,
        .open =                 pl2303_open,
        .close =                pl2303_close,
+       .dtr_rts =              pl2303_dtr_rts,
+       .carrier_raised =       pl2303_carrier_raised,
        .write =                pl2303_write,
        .ioctl =                pl2303_ioctl,
        .break_ctl =            pl2303_break_ctl,
index 913225c6161037ad78596f5ba68b9fa078f510b5..17ac34f4d66823deb49f02a571a09f28de07fe0a 100644 (file)
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
-#include <linux/usb/ch9.h>
 
 #define SWIMS_USB_REQUEST_SetPower     0x00
 #define SWIMS_USB_REQUEST_SetNmea      0x07
 
-/* per port private data */
 #define N_IN_URB       4
 #define N_OUT_URB      4
 #define IN_BUFLEN      4096
 static int debug;
 static int nmea;
 
+/* Used in interface blacklisting */
+struct sierra_iface_info {
+       const u32 infolen;      /* number of interface numbers on blacklist */
+       const u8  *ifaceinfo;   /* pointer to the array holding the numbers */
+};
+
 static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
 {
        int result;
@@ -85,6 +89,23 @@ static int sierra_calc_num_ports(struct usb_serial *serial)
        return result;
 }
 
+static int is_blacklisted(const u8 ifnum,
+                               const struct sierra_iface_info *blacklist)
+{
+       const u8  *info;
+       int i;
+
+       if (blacklist) {
+               info = blacklist->ifaceinfo;
+
+               for (i = 0; i < blacklist->infolen; i++) {
+                       if (info[i] == ifnum)
+                               return 1;
+               }
+       }
+       return 0;
+}
+
 static int sierra_calc_interface(struct usb_serial *serial)
 {
        int interface;
@@ -153,9 +174,25 @@ static int sierra_probe(struct usb_serial *serial,
         */
        usb_set_serial_data(serial, (void *)num_ports);
 
+       /* ifnum could have changed - by calling usb_set_interface */
+       ifnum = sierra_calc_interface(serial);
+
+       if (is_blacklisted(ifnum,
+                               (struct sierra_iface_info *)id->driver_info)) {
+               dev_dbg(&serial->dev->dev,
+                       "Ignoring blacklisted interface #%d\n", ifnum);
+               return -ENODEV;
+       }
+
        return result;
 }
 
+static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11 };
+static const struct sierra_iface_info direct_ip_interface_blacklist = {
+       .infolen = ARRAY_SIZE(direct_ip_non_serial_ifaces),
+       .ifaceinfo = direct_ip_non_serial_ifaces,
+};
+
 static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
@@ -188,9 +225,11 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781 */
        { USB_DEVICE(0x1199, 0x683A) }, /* Sierra Wireless MC8785 */
        { USB_DEVICE(0x1199, 0x683B) }, /* Sierra Wireless MC8785 Composite */
-       { USB_DEVICE(0x1199, 0x683C) }, /* Sierra Wireless MC8790 */
-       { USB_DEVICE(0x1199, 0x683D) }, /* Sierra Wireless MC8790 */
-       { USB_DEVICE(0x1199, 0x683E) }, /* Sierra Wireless MC8790 */
+       /* Sierra Wireless MC8790, MC8791, MC8792 Composite */
+       { USB_DEVICE(0x1199, 0x683C) },
+       { USB_DEVICE(0x1199, 0x683D) }, /* Sierra Wireless MC8791 Composite */
+       /* Sierra Wireless MC8790, MC8791, MC8792 */
+       { USB_DEVICE(0x1199, 0x683E) },
        { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
        { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
        { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */
@@ -211,6 +250,10 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
        { USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */
 
+       { USB_DEVICE(0x1199, 0x68A3),   /* Sierra Wireless Direct IP modems */
+         .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
+       },
+
        { }
 };
 MODULE_DEVICE_TABLE(usb, id_table);
@@ -229,7 +272,6 @@ struct sierra_port_private {
 
        /* Input endpoints and buffers for this port */
        struct urb *in_urbs[N_IN_URB];
-       char *in_buffer[N_IN_URB];
 
        /* Settings for the port */
        int rts_state;  /* Handshaking pins (outputs) */
@@ -240,57 +282,50 @@ struct sierra_port_private {
        int ri_state;
 };
 
-static int sierra_send_setup(struct tty_struct *tty,
-                                               struct usb_serial_port *port)
+static int sierra_send_setup(struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
        struct sierra_port_private *portdata;
        __u16 interface = 0;
+       int val = 0;
 
        dev_dbg(&port->dev, "%s", __func__);
 
        portdata = usb_get_serial_port_data(port);
 
-       if (tty) {
-               int val = 0;
-               if (portdata->dtr_state)
-                       val |= 0x01;
-               if (portdata->rts_state)
-                       val |= 0x02;
-
-               /* If composite device then properly report interface */
-               if (serial->num_ports == 1) {
-                       interface = sierra_calc_interface(serial);
-
-                       /* Control message is sent only to interfaces with
-                        * interrupt_in endpoints
-                        */
-                       if (port->interrupt_in_urb) {
-                               /* send control message */
-                               return usb_control_msg(serial->dev,
-                                       usb_rcvctrlpipe(serial->dev, 0),
-                                       0x22, 0x21, val, interface,
-                                       NULL, 0, USB_CTRL_SET_TIMEOUT);
-                       }
-               }
-
-               /* Otherwise the need to do non-composite mapping */
-               else {
-                       if (port->bulk_out_endpointAddress == 2)
-                               interface = 0;
-                       else if (port->bulk_out_endpointAddress == 4)
-                               interface = 1;
-                       else if (port->bulk_out_endpointAddress == 5)
-                               interface = 2;
+       if (portdata->dtr_state)
+               val |= 0x01;
+       if (portdata->rts_state)
+               val |= 0x02;
 
+       /* If composite device then properly report interface */
+       if (serial->num_ports == 1) {
+               interface = sierra_calc_interface(serial);
+               /* Control message is sent only to interfaces with
+                * interrupt_in endpoints
+                */
+               if (port->interrupt_in_urb) {
+                       /* send control message */
                        return usb_control_msg(serial->dev,
                                usb_rcvctrlpipe(serial->dev, 0),
                                0x22, 0x21, val, interface,
                                NULL, 0, USB_CTRL_SET_TIMEOUT);
-
                }
        }
 
+       /* Otherwise the need to do non-composite mapping */
+       else {
+               if (port->bulk_out_endpointAddress == 2)
+                       interface = 0;
+               else if (port->bulk_out_endpointAddress == 4)
+                       interface = 1;
+               else if (port->bulk_out_endpointAddress == 5)
+                       interface = 2;
+               return usb_control_msg(serial->dev,
+                       usb_rcvctrlpipe(serial->dev, 0),
+                       0x22, 0x21, val, interface,
+                       NULL, 0, USB_CTRL_SET_TIMEOUT);
+       }
        return 0;
 }
 
@@ -299,7 +334,7 @@ static void sierra_set_termios(struct tty_struct *tty,
 {
        dev_dbg(&port->dev, "%s", __func__);
        tty_termios_copy_hw(tty->termios, old_termios);
-       sierra_send_setup(tty, port);
+       sierra_send_setup(port);
 }
 
 static int sierra_tiocmget(struct tty_struct *tty, struct file *file)
@@ -338,7 +373,18 @@ static int sierra_tiocmset(struct tty_struct *tty, struct file *file,
                portdata->rts_state = 0;
        if (clear & TIOCM_DTR)
                portdata->dtr_state = 0;
-       return sierra_send_setup(tty, port);
+       return sierra_send_setup(port);
+}
+
+static void sierra_release_urb(struct urb *urb)
+{
+       struct usb_serial_port *port;
+       if (urb) {
+               port =  urb->context;
+               dev_dbg(&port->dev, "%s: %p\n", __func__, urb);
+               kfree(urb->transfer_buffer);
+               usb_free_urb(urb);
+       }
 }
 
 static void sierra_outdat_callback(struct urb *urb)
@@ -465,7 +511,7 @@ static void sierra_indat_callback(struct urb *urb)
                                " received", __func__);
 
                /* Resubmit urb so we continue receiving */
-               if (port->port.count && status != -ESHUTDOWN) {
+               if (port->port.count && status != -ESHUTDOWN && status != -EPERM) {
                        err = usb_submit_urb(urb, GFP_ATOMIC);
                        if (err)
                                dev_err(&port->dev, "resubmit read urb failed."
@@ -557,67 +603,99 @@ static int sierra_write_room(struct tty_struct *tty)
        return 2048;
 }
 
-static int sierra_open(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void sierra_stop_rx_urbs(struct usb_serial_port *port)
 {
-       struct sierra_port_private *portdata;
-       struct usb_serial *serial = port->serial;
        int i;
-       struct urb *urb;
-       int result;
+       struct sierra_port_private *portdata = usb_get_serial_port_data(port);
 
-       portdata = usb_get_serial_port_data(port);
+       for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++)
+               usb_kill_urb(portdata->in_urbs[i]);
 
-       dev_dbg(&port->dev, "%s", __func__);
+       usb_kill_urb(port->interrupt_in_urb);
+}
 
-       /* Set some sane defaults */
-       portdata->rts_state = 1;
-       portdata->dtr_state = 1;
+static int sierra_submit_rx_urbs(struct usb_serial_port *port, gfp_t mem_flags)
+{
+       int ok_cnt;
+       int err = -EINVAL;
+       int i;
+       struct urb *urb;
+       struct sierra_port_private *portdata = usb_get_serial_port_data(port);
 
-       /* Reset low level data toggle and start reading from endpoints */
-       for (i = 0; i < N_IN_URB; i++) {
+       ok_cnt = 0;
+       for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) {
                urb = portdata->in_urbs[i];
                if (!urb)
                        continue;
-               if (urb->dev != serial->dev) {
-                       dev_dbg(&port->dev, "%s: dev %p != %p",
-                                __func__, urb->dev, serial->dev);
-                       continue;
+               err = usb_submit_urb(urb, mem_flags);
+               if (err) {
+                       dev_err(&port->dev, "%s: submit urb failed: %d\n",
+                               __func__, err);
+               } else {
+                       ok_cnt++;
                }
+       }
 
-               /*
-                * make sure endpoint data toggle is synchronized with the
-                * device
-                */
-               usb_clear_halt(urb->dev, urb->pipe);
-
-               result = usb_submit_urb(urb, GFP_KERNEL);
-               if (result) {
-                       dev_err(&port->dev, "submit urb %d failed (%d) %d\n",
-                               i, result, urb->transfer_buffer_length);
+       if (ok_cnt && port->interrupt_in_urb) {
+               err = usb_submit_urb(port->interrupt_in_urb, mem_flags);
+               if (err) {
+                       dev_err(&port->dev, "%s: submit intr urb failed: %d\n",
+                               __func__, err);
                }
        }
 
-       sierra_send_setup(tty, port);
+       if (ok_cnt > 0) /* at least one rx urb submitted */
+               return 0;
+       else
+               return err;
+}
+
+static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint,
+                                       int dir, void *ctx, int len,
+                                       gfp_t mem_flags,
+                                       usb_complete_t callback)
+{
+       struct urb      *urb;
+       u8              *buf;
+
+       if (endpoint == -1)
+               return NULL;
 
-       /* start up the interrupt endpoint if we have one */
-       if (port->interrupt_in_urb) {
-               result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
-               if (result)
-                       dev_err(&port->dev, "submit irq_in urb failed %d\n",
-                               result);
+       urb = usb_alloc_urb(0, mem_flags);
+       if (urb == NULL) {
+               dev_dbg(&serial->dev->dev, "%s: alloc for endpoint %d failed\n",
+                       __func__, endpoint);
+               return NULL;
        }
-       return 0;
+
+       buf = kmalloc(len, mem_flags);
+       if (buf) {
+               /* Fill URB using supplied data */
+               usb_fill_bulk_urb(urb, serial->dev,
+                       usb_sndbulkpipe(serial->dev, endpoint) | dir,
+                       buf, len, callback, ctx);
+
+               /* debug */
+               dev_dbg(&serial->dev->dev, "%s %c u : %p d:%p\n", __func__,
+                               dir == USB_DIR_IN ? 'i' : 'o', urb, buf);
+       } else {
+               dev_dbg(&serial->dev->dev, "%s %c u:%p d:%p\n", __func__,
+                               dir == USB_DIR_IN ? 'i' : 'o', urb, buf);
+
+               sierra_release_urb(urb);
+               urb = NULL;
+       }
+
+       return urb;
 }
 
-static void sierra_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void sierra_close(struct usb_serial_port *port)
 {
        int i;
        struct usb_serial *serial = port->serial;
        struct sierra_port_private *portdata;
 
-       dev_dbg(&port->dev, "%s", __func__);
+       dev_dbg(&port->dev, "%s\n", __func__);
        portdata = usb_get_serial_port_data(port);
 
        portdata->rts_state = 0;
@@ -626,25 +704,83 @@ static void sierra_close(struct tty_struct *tty,
        if (serial->dev) {
                mutex_lock(&serial->disc_mutex);
                if (!serial->disconnected)
-                       sierra_send_setup(tty, port);
+                       sierra_send_setup(port);
                mutex_unlock(&serial->disc_mutex);
 
-               /* Stop reading/writing urbs */
-               for (i = 0; i < N_IN_URB; i++)
-                       usb_kill_urb(portdata->in_urbs[i]);
+               /* Stop reading urbs */
+               sierra_stop_rx_urbs(port);
+               /* .. and release them */
+               for (i = 0; i < N_IN_URB; i++) {
+                       sierra_release_urb(portdata->in_urbs[i]);
+                       portdata->in_urbs[i] = NULL;
+               }
        }
+}
 
-       usb_kill_urb(port->interrupt_in_urb);
-       tty_port_tty_set(&port->port, NULL);
+static int sierra_open(struct tty_struct *tty,
+                       struct usb_serial_port *port, struct file *filp)
+{
+       struct sierra_port_private *portdata;
+       struct usb_serial *serial = port->serial;
+       int i;
+       int err;
+       int endpoint;
+       struct urb *urb;
+
+       portdata = usb_get_serial_port_data(port);
+
+       dev_dbg(&port->dev, "%s", __func__);
+
+       /* Set some sane defaults */
+       portdata->rts_state = 1;
+       portdata->dtr_state = 1;
+
+
+       endpoint = port->bulk_in_endpointAddress;
+       for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) {
+               urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port,
+                                       IN_BUFLEN, GFP_KERNEL,
+                                       sierra_indat_callback);
+               portdata->in_urbs[i] = urb;
+       }
+       /* clear halt condition */
+       usb_clear_halt(serial->dev,
+                       usb_sndbulkpipe(serial->dev, endpoint) | USB_DIR_IN);
+
+       err = sierra_submit_rx_urbs(port, GFP_KERNEL);
+       if (err) {
+               /* get rid of everything as in close */
+               sierra_close(port);
+               return err;
+       }
+       sierra_send_setup(port);
+
+       return 0;
+}
+
+
+static void sierra_dtr_rts(struct usb_serial_port *port, int on)
+{
+       struct usb_serial *serial = port->serial;
+       struct sierra_port_private *portdata;
+
+       portdata = usb_get_serial_port_data(port);
+       portdata->rts_state = on;
+       portdata->dtr_state = on;
+
+       if (serial->dev) {
+               mutex_lock(&serial->disc_mutex);
+               if (!serial->disconnected)
+                       sierra_send_setup(port);
+               mutex_unlock(&serial->disc_mutex);
+       }
 }
 
 static int sierra_startup(struct usb_serial *serial)
 {
        struct usb_serial_port *port;
        struct sierra_port_private *portdata;
-       struct urb *urb;
        int i;
-       int j;
 
        dev_dbg(&serial->dev->dev, "%s", __func__);
 
@@ -666,34 +802,8 @@ static int sierra_startup(struct usb_serial *serial)
                        return -ENOMEM;
                }
                spin_lock_init(&portdata->lock);
-               for (j = 0; j < N_IN_URB; j++) {
-                       portdata->in_buffer[j] = kmalloc(IN_BUFLEN, GFP_KERNEL);
-                       if (!portdata->in_buffer[j]) {
-                               for (--j; j >= 0; j--)
-                                       kfree(portdata->in_buffer[j]);
-                               kfree(portdata);
-                               return -ENOMEM;
-                       }
-               }
-
+               /* Set the port private data pointer */
                usb_set_serial_port_data(port, portdata);
-
-               /* initialize the in urbs */
-               for (j = 0; j < N_IN_URB; ++j) {
-                       urb = usb_alloc_urb(0, GFP_KERNEL);
-                       if (urb == NULL) {
-                               dev_dbg(&port->dev, "%s: alloc for in "
-                                       "port failed.", __func__);
-                               continue;
-                       }
-                       /* Fill URB using supplied data. */
-                       usb_fill_bulk_urb(urb, serial->dev,
-                                         usb_rcvbulkpipe(serial->dev,
-                                               port->bulk_in_endpointAddress),
-                                         portdata->in_buffer[j], IN_BUFLEN,
-                                         sierra_indat_callback, port);
-                       portdata->in_urbs[j] = urb;
-               }
        }
 
        return 0;
@@ -701,7 +811,7 @@ static int sierra_startup(struct usb_serial *serial)
 
 static void sierra_shutdown(struct usb_serial *serial)
 {
-       int i, j;
+       int i;
        struct usb_serial_port *port;
        struct sierra_port_private *portdata;
 
@@ -714,12 +824,6 @@ static void sierra_shutdown(struct usb_serial *serial)
                portdata = usb_get_serial_port_data(port);
                if (!portdata)
                        continue;
-
-               for (j = 0; j < N_IN_URB; j++) {
-                       usb_kill_urb(portdata->in_urbs[j]);
-                       usb_free_urb(portdata->in_urbs[j]);
-                       kfree(portdata->in_buffer[j]);
-               }
                kfree(portdata);
                usb_set_serial_port_data(port, NULL);
        }
@@ -737,6 +841,7 @@ static struct usb_serial_driver sierra_device = {
        .probe             = sierra_probe,
        .open              = sierra_open,
        .close             = sierra_close,
+       .dtr_rts           = sierra_dtr_rts,
        .write             = sierra_write,
        .write_room        = sierra_write_room,
        .set_termios       = sierra_set_termios,
index 5e7528cc81a8e624f8ef64a869eca06b18918126..8f7ed8f13996185857021d7d2f730c08f60b2403 100644 (file)
@@ -446,66 +446,47 @@ static void spcp8x5_set_workMode(struct usb_device *dev, u16 value,
                        "RTSCTS usb_control_msg(enable flowctrl) = %d\n", ret);
 }
 
+static int spcp8x5_carrier_raised(struct usb_serial_port *port)
+{
+       struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+       if (priv->line_status & MSR_STATUS_LINE_DCD)
+               return 1;
+       return 0;
+}
+
+static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on)
+{
+       struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+       unsigned long flags;
+       u8 control;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (on)
+               priv->line_control = MCR_CONTROL_LINE_DTR
+                                               | MCR_CONTROL_LINE_RTS;
+       else
+               priv->line_control &= ~ (MCR_CONTROL_LINE_DTR
+                                               | MCR_CONTROL_LINE_RTS);
+       control = priv->line_control;
+       spin_unlock_irqrestore(&priv->lock, flags);
+       spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type);
+}
+
 /* close the serial port. We should wait for data sending to device 1st and
  * then kill all urb. */
-static void spcp8x5_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void spcp8x5_close(struct usb_serial_port *port)
 {
        struct spcp8x5_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
-       unsigned int c_cflag;
-       int bps;
-       long timeout;
-       wait_queue_t wait;
        int result;
 
        dbg("%s - port %d", __func__, port->number);
 
-       /* wait for data to drain from the buffer */
        spin_lock_irqsave(&priv->lock, flags);
-       timeout = SPCP8x5_CLOSING_WAIT;
-       init_waitqueue_entry(&wait, current);
-       add_wait_queue(&tty->write_wait, &wait);
-       for (;;) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (ringbuf_avail_data(priv->buf) == 0 ||
-                   timeout == 0 || signal_pending(current))
-                       break;
-               spin_unlock_irqrestore(&priv->lock, flags);
-               timeout = schedule_timeout(timeout);
-               spin_lock_irqsave(&priv->lock, flags);
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&tty->write_wait, &wait);
-
        /* clear out any remaining data in the buffer */
        clear_ringbuf(priv->buf);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       /* wait for characters to drain from the device (this is long enough
-        * for the entire all byte spcp8x5 hardware buffer to drain with no
-        * flow control for data rates of 1200 bps or more, for lower rates we
-        * should really know how much data is in the buffer to compute a delay
-        * that is not unnecessarily long) */
-       bps = tty_get_baud_rate(tty);
-       if (bps > 1200)
-               timeout = max((HZ*2560) / bps, HZ/10);
-       else
-               timeout = 2*HZ;
-       set_current_state(TASK_INTERRUPTIBLE);
-       schedule_timeout(timeout);
-
-       /* clear control lines */
-       if (tty) {
-               c_cflag = tty->termios->c_cflag;
-               if (c_cflag & HUPCL) {
-                       spin_lock_irqsave(&priv->lock, flags);
-                       priv->line_control = 0;
-                       spin_unlock_irqrestore(&priv->lock, flags);
-                       spcp8x5_set_ctrlLine(port->serial->dev, 0 , priv->type);
-               }
-       }
-
        /* kill urb */
        if (port->write_urb != NULL) {
                result = usb_unlink_urb(port->write_urb);
@@ -665,13 +646,6 @@ static int spcp8x5_open(struct tty_struct *tty,
        if (ret)
                return ret;
 
-       spin_lock_irqsave(&priv->lock, flags);
-       if (tty && (tty->termios->c_cflag & CBAUD))
-               priv->line_control = MCR_DTR | MCR_RTS;
-       else
-               priv->line_control = 0;
-       spin_unlock_irqrestore(&priv->lock, flags);
-
        spcp8x5_set_ctrlLine(serial->dev, priv->line_control , priv->type);
 
        /* Setup termios */
@@ -691,9 +665,10 @@ static int spcp8x5_open(struct tty_struct *tty,
        port->read_urb->dev = serial->dev;
        ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
        if (ret) {
-               spcp8x5_close(tty, port, NULL);
+               spcp8x5_close(port);
                return -EPROTO;
        }
+       port->port.drain_delay = 256;
        return 0;
 }
 
@@ -1033,6 +1008,8 @@ static struct usb_serial_driver spcp8x5_device = {
        .num_ports              = 1,
        .open                   = spcp8x5_open,
        .close                  = spcp8x5_close,
+       .dtr_rts                = spcp8x5_dtr_rts,
+       .carrier_raised         = spcp8x5_carrier_raised,
        .write                  = spcp8x5_write,
        .set_termios            = spcp8x5_set_termios,
        .ioctl                  = spcp8x5_ioctl,
index 69879e4379402f63ad53579c6a1184d762322260..8b07ebc6baeb4e40ba036e07cacee5414b508628 100644 (file)
@@ -152,8 +152,7 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port,
        return result;
 }
 
-static void symbol_close(struct tty_struct *tty, struct usb_serial_port *port,
-                         struct file *filp)
+static void symbol_close(struct usb_serial_port *port)
 {
        struct symbol_private *priv = usb_get_serial_data(port->serial);
 
index 0a64bac306ee693f02e9b11ce20a2a70cf452965..42cb04c403beee3900e6fa33451913d0e0a3b29e 100644 (file)
@@ -100,8 +100,7 @@ static int ti_startup(struct usb_serial *serial);
 static void ti_shutdown(struct usb_serial *serial);
 static int ti_open(struct tty_struct *tty, struct usb_serial_port *port,
                struct file *file);
-static void ti_close(struct tty_struct *tty, struct usb_serial_port *port,
-               struct file *file);
+static void ti_close(struct usb_serial_port *port);
 static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
                const unsigned char *data, int count);
 static int ti_write_room(struct tty_struct *tty);
@@ -647,8 +646,7 @@ release_lock:
 }
 
 
-static void ti_close(struct tty_struct *tty, struct usb_serial_port *port,
-                                                       struct file *file)
+static void ti_close(struct usb_serial_port *port)
 {
        struct ti_device *tdev;
        struct ti_port *tport;
index f331e2bde88acbb0c2b4e36fee01eff68ffc9b5c..1967a7edc10c51fab8263aafc43a425a2b28e686 100644 (file)
@@ -238,9 +238,11 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
                        goto bailout_interface_put;
                mutex_unlock(&serial->disc_mutex);
        }
-
        mutex_unlock(&port->mutex);
-       return 0;
+       /* Now do the correct tty layer semantics */
+       retval = tty_port_block_til_ready(&port->port, tty, filp);
+       if (retval == 0)
+               return 0;
 
 bailout_interface_put:
        usb_autopm_put_interface(serial->interface);
@@ -259,64 +261,89 @@ bailout_serial_put:
        return retval;
 }
 
-static void serial_close(struct tty_struct *tty, struct file *filp)
+/**
+ *     serial_do_down          -       shut down hardware
+ *     @port: port to shut down
+ *
+ *     Shut down a USB port unless it is the console. We never shut down the
+ *     console hardware as it will always be in use.
+ *
+ *     Don't free any resources at this point
+ */
+static void serial_do_down(struct usb_serial_port *port)
 {
-       struct usb_serial_port *port = tty->driver_data;
+       struct usb_serial_driver *drv = port->serial->type;
        struct usb_serial *serial;
        struct module *owner;
-       int count;
 
-       if (!port)
+       /* The console is magical, do not hang up the console hardware
+          or there will be tears */
+       if (port->console)
                return;
 
-       dbg("%s - port %d", __func__, port->number);
-
        mutex_lock(&port->mutex);
        serial = port->serial;
        owner = serial->type->driver.owner;
 
-       if (port->port.count == 0) {
-               mutex_unlock(&port->mutex);
-               return;
-       }
-
-       if (port->port.count == 1)
-               /* only call the device specific close if this
-                * port is being closed by the last owner. Ensure we do
-                * this before we drop the port count. The call is protected
-                * by the port mutex
-                */
-               serial->type->close(tty, port, filp);
-
-       if (port->port.count == (port->console ? 2 : 1)) {
-               struct tty_struct *tty = tty_port_tty_get(&port->port);
-               if (tty) {
-                       /* We must do this before we drop the port count to
-                          zero. */
-                       if (tty->driver_data)
-                               tty->driver_data = NULL;
-                       tty_port_tty_set(&port->port, NULL);
-                       tty_kref_put(tty);
-               }
-       }
+       if (drv->close)
+               drv->close(port);
 
-       --port->port.count;
-       count = port->port.count;
        mutex_unlock(&port->mutex);
-       put_device(&port->dev);
+}
+
+/**
+ *     serial_do_free          -       free resources post close/hangup
+ *     @port: port to free up
+ *
+ *     Do the resource freeing and refcount dropping for the port. We must
+ *     be careful about ordering and we must avoid freeing up the console.
+ */
 
+static void serial_do_free(struct usb_serial_port *port)
+{
+       struct usb_serial *serial;
+       struct module *owner;
+
+       /* The console is magical, do not hang up the console hardware
+          or there will be tears */
+       if (port->console)
+               return;
+
+       serial = port->serial;
+       owner = serial->type->driver.owner;
+       put_device(&port->dev);
        /* Mustn't dereference port any more */
-       if (count == 0) {
-               mutex_lock(&serial->disc_mutex);
-               if (!serial->disconnected)
-                       usb_autopm_put_interface(serial->interface);
-               mutex_unlock(&serial->disc_mutex);
-       }
+       mutex_lock(&serial->disc_mutex);
+       if (!serial->disconnected)
+               usb_autopm_put_interface(serial->interface);
+       mutex_unlock(&serial->disc_mutex);
        usb_serial_put(serial);
-
        /* Mustn't dereference serial any more */
-       if (count == 0)
-               module_put(owner);
+       module_put(owner);
+}
+
+static void serial_close(struct tty_struct *tty, struct file *filp)
+{
+       struct usb_serial_port *port = tty->driver_data;
+
+       dbg("%s - port %d", __func__, port->number);
+
+
+       if (tty_port_close_start(&port->port, tty, filp) == 0)
+               return;
+
+       serial_do_down(port);           
+       tty_port_close_end(&port->port, tty);
+       tty_port_tty_set(&port->port, NULL);
+       serial_do_free(port);
+}
+
+static void serial_hangup(struct tty_struct *tty)
+{
+       struct usb_serial_port *port = tty->driver_data;
+       serial_do_down(port);
+       tty_port_hangup(&port->port);
+       serial_do_free(port);
 }
 
 static int serial_write(struct tty_struct *tty, const unsigned char *buf,
@@ -648,6 +675,29 @@ static struct usb_serial_driver *search_serial_device(
        return NULL;
 }
 
+static int serial_carrier_raised(struct tty_port *port)
+{
+       struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
+       struct usb_serial_driver *drv = p->serial->type;
+       if (drv->carrier_raised)
+               return drv->carrier_raised(p);
+       /* No carrier control - don't block */
+       return 1;       
+}
+
+static void serial_dtr_rts(struct tty_port *port, int on)
+{
+       struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
+       struct usb_serial_driver *drv = p->serial->type;
+       if (drv->dtr_rts)
+               drv->dtr_rts(p, on);
+}
+
+static const struct tty_port_operations serial_port_ops = {
+       .carrier_raised = serial_carrier_raised,
+       .dtr_rts = serial_dtr_rts,
+};
+
 int usb_serial_probe(struct usb_interface *interface,
                               const struct usb_device_id *id)
 {
@@ -841,6 +891,7 @@ int usb_serial_probe(struct usb_interface *interface,
                if (!port)
                        goto probe_error;
                tty_port_init(&port->port);
+               port->port.ops = &serial_port_ops;
                port->serial = serial;
                spin_lock_init(&port->lock);
                mutex_init(&port->mutex);
@@ -1071,6 +1122,9 @@ void usb_serial_disconnect(struct usb_interface *interface)
                if (port) {
                        struct tty_struct *tty = tty_port_tty_get(&port->port);
                        if (tty) {
+                               /* The hangup will occur asynchronously but
+                                  the object refcounts will sort out all the
+                                  cleanup */
                                tty_hangup(tty);
                                tty_kref_put(tty);
                        }
@@ -1135,6 +1189,7 @@ static const struct tty_operations serial_ops = {
        .open =                 serial_open,
        .close =                serial_close,
        .write =                serial_write,
+       .hangup =               serial_hangup,
        .write_room =           serial_write_room,
        .ioctl =                serial_ioctl,
        .set_termios =          serial_set_termios,
@@ -1147,6 +1202,7 @@ static const struct tty_operations serial_ops = {
        .proc_fops =            &serial_proc_fops,
 };
 
+
 struct tty_driver *usb_serial_tty_driver;
 
 static int __init usb_serial_init(void)
index 5ac414bda718103191d6489f613e3d5d3c361dd6..b15f1c0e1d4acba4adcbadf66ac98a9870e8c994 100644 (file)
@@ -38,8 +38,7 @@
 /* function prototypes for a handspring visor */
 static int  visor_open(struct tty_struct *tty, struct usb_serial_port *port,
                                        struct file *filp);
-static void visor_close(struct tty_struct *tty, struct usb_serial_port *port,
-                                       struct file *filp);
+static void visor_close(struct usb_serial_port *port);
 static int  visor_write(struct tty_struct *tty, struct usb_serial_port *port,
                                        const unsigned char *buf, int count);
 static int  visor_write_room(struct tty_struct *tty);
@@ -324,8 +323,7 @@ exit:
 }
 
 
-static void visor_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void visor_close(struct usb_serial_port *port)
 {
        struct visor_private *priv = usb_get_serial_port_data(port);
        unsigned char *transfer_buffer;
index 5335d3211c073c1c661d895aeaa0488fa0196ba1..7c7295d09f344cf7b4b167346e140e75d6394207 100644 (file)
@@ -147,8 +147,7 @@ static int  whiteheat_attach(struct usb_serial *serial);
 static void whiteheat_shutdown(struct usb_serial *serial);
 static int  whiteheat_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
-static void whiteheat_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp);
+static void whiteheat_close(struct usb_serial_port *port);
 static int  whiteheat_write(struct tty_struct *tty,
                        struct usb_serial_port *port,
                        const unsigned char *buf, int count);
@@ -712,8 +711,7 @@ exit:
 }
 
 
-static void whiteheat_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void whiteheat_close(struct usb_serial_port *port)
 {
        struct whiteheat_private *info = usb_get_serial_port_data(port);
        struct whiteheat_urb_wrap *wrap;
@@ -723,31 +721,7 @@ static void whiteheat_close(struct tty_struct *tty,
 
        dbg("%s - port %d", __func__, port->number);
 
-       mutex_lock(&port->serial->disc_mutex);
-       /* filp is NULL when called from usb_serial_disconnect */
-       if ((filp && (tty_hung_up_p(filp))) || port->serial->disconnected) {
-               mutex_unlock(&port->serial->disc_mutex);
-               return;
-       }
-       mutex_unlock(&port->serial->disc_mutex);
-
-       tty->closing = 1;
-
-/*
- * Not currently in use; tty_wait_until_sent() calls
- * serial_chars_in_buffer() which deadlocks on the second semaphore
- * acquisition. This should be fixed at some point. Greg's been
- * notified.
-       if ((filp->f_flags & (O_NDELAY | O_NONBLOCK)) == 0) {
-               tty_wait_until_sent(tty, CLOSING_DELAY);
-       }
-*/
-
-       tty_driver_flush_buffer(tty);
-       tty_ldisc_flush(tty);
-
        firm_report_tx_done(port);
-
        firm_close(port);
 
        /* shutdown our bulk reads and writes */
@@ -775,10 +749,7 @@ static void whiteheat_close(struct tty_struct *tty,
        }
        spin_unlock_irq(&info->lock);
        mutex_unlock(&info->deathwarrant);
-
        stop_command_port(port->serial);
-
-       tty->closing = 0;
 }
 
 
index 4ca3b586064375c939ae195e260221b519ed06d0..cfa26d56ce60c4f2c69346aae433444a5c812297 100644 (file)
@@ -132,7 +132,7 @@ static int slave_configure(struct scsi_device *sdev)
 
                if (us->fflags & US_FL_MAX_SECTORS_MIN)
                        max_sectors = PAGE_CACHE_SIZE >> 9;
-               if (sdev->request_queue->max_sectors > max_sectors)
+               if (queue_max_sectors(sdev->request_queue) > max_sectors)
                        blk_queue_max_sectors(sdev->request_queue,
                                              max_sectors);
        } else if (sdev->type == TYPE_TAPE) {
@@ -483,7 +483,7 @@ static ssize_t show_max_sectors(struct device *dev, struct device_attribute *att
 {
        struct scsi_device *sdev = to_scsi_device(dev);
 
-       return sprintf(buf, "%u\n", sdev->request_queue->max_sectors);
+       return sprintf(buf, "%u\n", queue_max_sectors(sdev->request_queue));
 }
 
 /* Input routine for the sysfs max_sectors file */
index e6467cf9f19f17ff4269168755d2ee5bd9ea5ec3..020db7fc9153ab1f3483909ccd02f76b9e455900 100644 (file)
@@ -335,9 +335,9 @@ static int __init hitfb_probe(struct platform_device *dev)
        if (fb_get_options("hitfb", NULL))
                return -ENODEV;
 
-       hitfb_fix.mmio_start = CONFIG_HD64461_IOBASE+0x1000;
+       hitfb_fix.mmio_start = HD64461_IO_OFFSET(0x1000);
        hitfb_fix.mmio_len = 0x1000;
-       hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000;
+       hitfb_fix.smem_start = HD64461_IO_OFFSET(0x02000000);
        hitfb_fix.smem_len = 512 * 1024;
 
        lcdclor = fb_readw(HD64461_LCDCLOR);
index 8ac9cddac5754fdbf8ef9df33550a47bfba318f4..cab100acf983905b53d5c85b6ae76496d7b9b7c8 100644 (file)
@@ -18,6 +18,16 @@ config XEN_SCRUB_PAGES
          secure, but slightly less efficient.
          If in doubt, say yes.
 
+config XEN_DEV_EVTCHN
+       tristate "Xen /dev/xen/evtchn device"
+       depends on XEN
+       default y
+       help
+         The evtchn driver allows a userspace process to triger event
+         channels and to receive notification of an event channel
+         firing.
+         If in doubt, say yes.
+
 config XENFS
        tristate "Xen filesystem"
        depends on XEN
@@ -41,3 +51,13 @@ config XEN_COMPAT_XENFS
          a xen platform.
          If in doubt, say yes.
 
+config XEN_SYS_HYPERVISOR
+       bool "Create xen entries under /sys/hypervisor"
+       depends on XEN && SYSFS
+       select SYS_HYPERVISOR
+       default y
+       help
+         Create entries under /sys/hypervisor describing the Xen
+        hypervisor environment.  When running native or in another
+        virtual environment, /sys/hypervisor will still be present,
+        but will have no xen contents.
\ No newline at end of file
index ff8accc9e103f9d2a4fc21dcbcc2e88d479a0ade..ec2a39b1e26f0438f6a2266cd77ff6173fd7bbc7 100644 (file)
@@ -4,4 +4,6 @@ obj-y   += xenbus/
 obj-$(CONFIG_HOTPLUG_CPU)      += cpu_hotplug.o
 obj-$(CONFIG_XEN_XENCOMM)      += xencomm.o
 obj-$(CONFIG_XEN_BALLOON)      += balloon.o
-obj-$(CONFIG_XENFS)            += xenfs/
\ No newline at end of file
+obj-$(CONFIG_XEN_DEV_EVTCHN)   += evtchn.o
+obj-$(CONFIG_XENFS)            += xenfs/
+obj-$(CONFIG_XEN_SYS_HYPERVISOR)       += sys-hypervisor.o
\ No newline at end of file
index 30963af5dba02960143f9ebf37b6f85d44de0dec..891d2e90753ab6e9dd312b3120ce6904a96058c2 100644 (file)
@@ -151,6 +151,12 @@ static unsigned int evtchn_from_irq(unsigned irq)
        return info_for_irq(irq)->evtchn;
 }
 
+unsigned irq_from_evtchn(unsigned int evtchn)
+{
+       return evtchn_to_irq[evtchn];
+}
+EXPORT_SYMBOL_GPL(irq_from_evtchn);
+
 static enum ipi_vector ipi_from_irq(unsigned irq)
 {
        struct irq_info *info = info_for_irq(irq);
@@ -335,7 +341,7 @@ static int find_unbound_irq(void)
        if (irq == nr_irqs)
                panic("No available IRQ to bind to: increase nr_irqs!\n");
 
-       desc = irq_to_desc_alloc_cpu(irq, 0);
+       desc = irq_to_desc_alloc_node(irq, 0);
        if (WARN_ON(desc == NULL))
                return -1;
 
@@ -688,13 +694,13 @@ void rebind_evtchn_irq(int evtchn, int irq)
 }
 
 /* Rebind an evtchn so that it gets delivered to a specific cpu */
-static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
+static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
 {
        struct evtchn_bind_vcpu bind_vcpu;
        int evtchn = evtchn_from_irq(irq);
 
        if (!VALID_EVTCHN(evtchn))
-               return;
+               return -1;
 
        /* Send future instances of this interrupt to other vcpu. */
        bind_vcpu.port = evtchn;
@@ -707,13 +713,15 @@ static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
         */
        if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
                bind_evtchn_to_cpu(evtchn, tcpu);
-}
 
+       return 0;
+}
 
-static void set_affinity_irq(unsigned irq, const struct cpumask *dest)
+static int set_affinity_irq(unsigned irq, const struct cpumask *dest)
 {
        unsigned tcpu = cpumask_first(dest);
-       rebind_irq_to_cpu(irq, tcpu);
+
+       return rebind_irq_to_cpu(irq, tcpu);
 }
 
 int resend_irq_on_evtchn(unsigned int irq)
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
new file mode 100644 (file)
index 0000000..af03195
--- /dev/null
@@ -0,0 +1,507 @@
+/******************************************************************************
+ * evtchn.c
+ *
+ * Driver for receiving and demuxing event-channel signals.
+ *
+ * Copyright (c) 2004-2005, K A Fraser
+ * Multi-process extensions Copyright (c) 2004, Steven Smith
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/major.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/poll.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/gfp.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <xen/events.h>
+#include <xen/evtchn.h>
+#include <asm/xen/hypervisor.h>
+
+struct per_user_data {
+       struct mutex bind_mutex; /* serialize bind/unbind operations */
+
+       /* Notification ring, accessed via /dev/xen/evtchn. */
+#define EVTCHN_RING_SIZE     (PAGE_SIZE / sizeof(evtchn_port_t))
+#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1))
+       evtchn_port_t *ring;
+       unsigned int ring_cons, ring_prod, ring_overflow;
+       struct mutex ring_cons_mutex; /* protect against concurrent readers */
+
+       /* Processes wait on this queue when ring is empty. */
+       wait_queue_head_t evtchn_wait;
+       struct fasync_struct *evtchn_async_queue;
+       const char *name;
+};
+
+/* Who's bound to each port? */
+static struct per_user_data *port_user[NR_EVENT_CHANNELS];
+static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */
+
+irqreturn_t evtchn_interrupt(int irq, void *data)
+{
+       unsigned int port = (unsigned long)data;
+       struct per_user_data *u;
+
+       spin_lock(&port_user_lock);
+
+       u = port_user[port];
+
+       disable_irq_nosync(irq);
+
+       if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
+               u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port;
+               wmb(); /* Ensure ring contents visible */
+               if (u->ring_cons == u->ring_prod++) {
+                       wake_up_interruptible(&u->evtchn_wait);
+                       kill_fasync(&u->evtchn_async_queue,
+                                   SIGIO, POLL_IN);
+               }
+       } else {
+               u->ring_overflow = 1;
+       }
+
+       spin_unlock(&port_user_lock);
+
+       return IRQ_HANDLED;
+}
+
+static ssize_t evtchn_read(struct file *file, char __user *buf,
+                          size_t count, loff_t *ppos)
+{
+       int rc;
+       unsigned int c, p, bytes1 = 0, bytes2 = 0;
+       struct per_user_data *u = file->private_data;
+
+       /* Whole number of ports. */
+       count &= ~(sizeof(evtchn_port_t)-1);
+
+       if (count == 0)
+               return 0;
+
+       if (count > PAGE_SIZE)
+               count = PAGE_SIZE;
+
+       for (;;) {
+               mutex_lock(&u->ring_cons_mutex);
+
+               rc = -EFBIG;
+               if (u->ring_overflow)
+                       goto unlock_out;
+
+               c = u->ring_cons;
+               p = u->ring_prod;
+               if (c != p)
+                       break;
+
+               mutex_unlock(&u->ring_cons_mutex);
+
+               if (file->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+
+               rc = wait_event_interruptible(u->evtchn_wait,
+                                             u->ring_cons != u->ring_prod);
+               if (rc)
+                       return rc;
+       }
+
+       /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
+       if (((c ^ p) & EVTCHN_RING_SIZE) != 0) {
+               bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) *
+                       sizeof(evtchn_port_t);
+               bytes2 = EVTCHN_RING_MASK(p) * sizeof(evtchn_port_t);
+       } else {
+               bytes1 = (p - c) * sizeof(evtchn_port_t);
+               bytes2 = 0;
+       }
+
+       /* Truncate chunks according to caller's maximum byte count. */
+       if (bytes1 > count) {
+               bytes1 = count;
+               bytes2 = 0;
+       } else if ((bytes1 + bytes2) > count) {
+               bytes2 = count - bytes1;
+       }
+
+       rc = -EFAULT;
+       rmb(); /* Ensure that we see the port before we copy it. */
+       if (copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) ||
+           ((bytes2 != 0) &&
+            copy_to_user(&buf[bytes1], &u->ring[0], bytes2)))
+               goto unlock_out;
+
+       u->ring_cons += (bytes1 + bytes2) / sizeof(evtchn_port_t);
+       rc = bytes1 + bytes2;
+
+ unlock_out:
+       mutex_unlock(&u->ring_cons_mutex);
+       return rc;
+}
+
+static ssize_t evtchn_write(struct file *file, const char __user *buf,
+                           size_t count, loff_t *ppos)
+{
+       int rc, i;
+       evtchn_port_t *kbuf = (evtchn_port_t *)__get_free_page(GFP_KERNEL);
+       struct per_user_data *u = file->private_data;
+
+       if (kbuf == NULL)
+               return -ENOMEM;
+
+       /* Whole number of ports. */
+       count &= ~(sizeof(evtchn_port_t)-1);
+
+       rc = 0;
+       if (count == 0)
+               goto out;
+
+       if (count > PAGE_SIZE)
+               count = PAGE_SIZE;
+
+       rc = -EFAULT;
+       if (copy_from_user(kbuf, buf, count) != 0)
+               goto out;
+
+       spin_lock_irq(&port_user_lock);
+       for (i = 0; i < (count/sizeof(evtchn_port_t)); i++)
+               if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u))
+                       enable_irq(irq_from_evtchn(kbuf[i]));
+       spin_unlock_irq(&port_user_lock);
+
+       rc = count;
+
+ out:
+       free_page((unsigned long)kbuf);
+       return rc;
+}
+
+static int evtchn_bind_to_user(struct per_user_data *u, int port)
+{
+       int rc = 0;
+
+       /*
+        * Ports are never reused, so every caller should pass in a
+        * unique port.
+        *
+        * (Locking not necessary because we haven't registered the
+        * interrupt handler yet, and our caller has already
+        * serialized bind operations.)
+        */
+       BUG_ON(port_user[port] != NULL);
+       port_user[port] = u;
+
+       rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED,
+                                      u->name, (void *)(unsigned long)port);
+       if (rc >= 0)
+               rc = 0;
+
+       return rc;
+}
+
+static void evtchn_unbind_from_user(struct per_user_data *u, int port)
+{
+       int irq = irq_from_evtchn(port);
+
+       unbind_from_irqhandler(irq, (void *)(unsigned long)port);
+
+       /* make sure we unbind the irq handler before clearing the port */
+       barrier();
+
+       port_user[port] = NULL;
+}
+
+static long evtchn_ioctl(struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       int rc;
+       struct per_user_data *u = file->private_data;
+       void __user *uarg = (void __user *) arg;
+
+       /* Prevent bind from racing with unbind */
+       mutex_lock(&u->bind_mutex);
+
+       switch (cmd) {
+       case IOCTL_EVTCHN_BIND_VIRQ: {
+               struct ioctl_evtchn_bind_virq bind;
+               struct evtchn_bind_virq bind_virq;
+
+               rc = -EFAULT;
+               if (copy_from_user(&bind, uarg, sizeof(bind)))
+                       break;
+
+               bind_virq.virq = bind.virq;
+               bind_virq.vcpu = 0;
+               rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
+                                                &bind_virq);
+               if (rc != 0)
+                       break;
+
+               rc = evtchn_bind_to_user(u, bind_virq.port);
+               if (rc == 0)
+                       rc = bind_virq.port;
+               break;
+       }
+
+       case IOCTL_EVTCHN_BIND_INTERDOMAIN: {
+               struct ioctl_evtchn_bind_interdomain bind;
+               struct evtchn_bind_interdomain bind_interdomain;
+
+               rc = -EFAULT;
+               if (copy_from_user(&bind, uarg, sizeof(bind)))
+                       break;
+
+               bind_interdomain.remote_dom  = bind.remote_domain;
+               bind_interdomain.remote_port = bind.remote_port;
+               rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
+                                                &bind_interdomain);
+               if (rc != 0)
+                       break;
+
+               rc = evtchn_bind_to_user(u, bind_interdomain.local_port);
+               if (rc == 0)
+                       rc = bind_interdomain.local_port;
+               break;
+       }
+
+       case IOCTL_EVTCHN_BIND_UNBOUND_PORT: {
+               struct ioctl_evtchn_bind_unbound_port bind;
+               struct evtchn_alloc_unbound alloc_unbound;
+
+               rc = -EFAULT;
+               if (copy_from_user(&bind, uarg, sizeof(bind)))
+                       break;
+
+               alloc_unbound.dom        = DOMID_SELF;
+               alloc_unbound.remote_dom = bind.remote_domain;
+               rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+                                                &alloc_unbound);
+               if (rc != 0)
+                       break;
+
+               rc = evtchn_bind_to_user(u, alloc_unbound.port);
+               if (rc == 0)
+                       rc = alloc_unbound.port;
+               break;
+       }
+
+       case IOCTL_EVTCHN_UNBIND: {
+               struct ioctl_evtchn_unbind unbind;
+
+               rc = -EFAULT;
+               if (copy_from_user(&unbind, uarg, sizeof(unbind)))
+                       break;
+
+               rc = -EINVAL;
+               if (unbind.port >= NR_EVENT_CHANNELS)
+                       break;
+
+               spin_lock_irq(&port_user_lock);
+
+               rc = -ENOTCONN;
+               if (port_user[unbind.port] != u) {
+                       spin_unlock_irq(&port_user_lock);
+                       break;
+               }
+
+               evtchn_unbind_from_user(u, unbind.port);
+
+               spin_unlock_irq(&port_user_lock);
+
+               rc = 0;
+               break;
+       }
+
+       case IOCTL_EVTCHN_NOTIFY: {
+               struct ioctl_evtchn_notify notify;
+
+               rc = -EFAULT;
+               if (copy_from_user(&notify, uarg, sizeof(notify)))
+                       break;
+
+               if (notify.port >= NR_EVENT_CHANNELS) {
+                       rc = -EINVAL;
+               } else if (port_user[notify.port] != u) {
+                       rc = -ENOTCONN;
+               } else {
+                       notify_remote_via_evtchn(notify.port);
+                       rc = 0;
+               }
+               break;
+       }
+
+       case IOCTL_EVTCHN_RESET: {
+               /* Initialise the ring to empty. Clear errors. */
+               mutex_lock(&u->ring_cons_mutex);
+               spin_lock_irq(&port_user_lock);
+               u->ring_cons = u->ring_prod = u->ring_overflow = 0;
+               spin_unlock_irq(&port_user_lock);
+               mutex_unlock(&u->ring_cons_mutex);
+               rc = 0;
+               break;
+       }
+
+       default:
+               rc = -ENOSYS;
+               break;
+       }
+       mutex_unlock(&u->bind_mutex);
+
+       return rc;
+}
+
+static unsigned int evtchn_poll(struct file *file, poll_table *wait)
+{
+       unsigned int mask = POLLOUT | POLLWRNORM;
+       struct per_user_data *u = file->private_data;
+
+       poll_wait(file, &u->evtchn_wait, wait);
+       if (u->ring_cons != u->ring_prod)
+               mask |= POLLIN | POLLRDNORM;
+       if (u->ring_overflow)
+               mask = POLLERR;
+       return mask;
+}
+
+static int evtchn_fasync(int fd, struct file *filp, int on)
+{
+       struct per_user_data *u = filp->private_data;
+       return fasync_helper(fd, filp, on, &u->evtchn_async_queue);
+}
+
+static int evtchn_open(struct inode *inode, struct file *filp)
+{
+       struct per_user_data *u;
+
+       u = kzalloc(sizeof(*u), GFP_KERNEL);
+       if (u == NULL)
+               return -ENOMEM;
+
+       u->name = kasprintf(GFP_KERNEL, "evtchn:%s", current->comm);
+       if (u->name == NULL) {
+               kfree(u);
+               return -ENOMEM;
+       }
+
+       init_waitqueue_head(&u->evtchn_wait);
+
+       u->ring = (evtchn_port_t *)__get_free_page(GFP_KERNEL);
+       if (u->ring == NULL) {
+               kfree(u->name);
+               kfree(u);
+               return -ENOMEM;
+       }
+
+       mutex_init(&u->bind_mutex);
+       mutex_init(&u->ring_cons_mutex);
+
+       filp->private_data = u;
+
+       return 0;
+}
+
+static int evtchn_release(struct inode *inode, struct file *filp)
+{
+       int i;
+       struct per_user_data *u = filp->private_data;
+
+       spin_lock_irq(&port_user_lock);
+
+       free_page((unsigned long)u->ring);
+
+       for (i = 0; i < NR_EVENT_CHANNELS; i++) {
+               if (port_user[i] != u)
+                       continue;
+
+               evtchn_unbind_from_user(port_user[i], i);
+       }
+
+       spin_unlock_irq(&port_user_lock);
+
+       kfree(u->name);
+       kfree(u);
+
+       return 0;
+}
+
+static const struct file_operations evtchn_fops = {
+       .owner   = THIS_MODULE,
+       .read    = evtchn_read,
+       .write   = evtchn_write,
+       .unlocked_ioctl = evtchn_ioctl,
+       .poll    = evtchn_poll,
+       .fasync  = evtchn_fasync,
+       .open    = evtchn_open,
+       .release = evtchn_release,
+};
+
+static struct miscdevice evtchn_miscdev = {
+       .minor        = MISC_DYNAMIC_MINOR,
+       .name         = "evtchn",
+       .fops         = &evtchn_fops,
+};
+static int __init evtchn_init(void)
+{
+       int err;
+
+       if (!xen_domain())
+               return -ENODEV;
+
+       spin_lock_init(&port_user_lock);
+       memset(port_user, 0, sizeof(port_user));
+
+       /* Create '/dev/misc/evtchn'. */
+       err = misc_register(&evtchn_miscdev);
+       if (err != 0) {
+               printk(KERN_ALERT "Could not register /dev/misc/evtchn\n");
+               return err;
+       }
+
+       printk(KERN_INFO "Event-channel device installed.\n");
+
+       return 0;
+}
+
+static void __exit evtchn_cleanup(void)
+{
+       misc_deregister(&evtchn_miscdev);
+}
+
+module_init(evtchn_init);
+module_exit(evtchn_cleanup);
+
+MODULE_LICENSE("GPL");
index 4b5b84837ee13c85fab14a73c7ab213f74af90e2..fddc2025dece777c513a7a7a72f8537751bf1834 100644 (file)
@@ -98,9 +98,8 @@ static void do_suspend(void)
                goto out;
        }
 
-       printk("suspending xenbus...\n");
-       /* XXX use normal device tree? */
-       xenbus_suspend();
+       printk(KERN_DEBUG "suspending xenstore...\n");
+       xs_suspend();
 
        err = device_power_down(PMSG_SUSPEND);
        if (err) {
@@ -116,9 +115,9 @@ static void do_suspend(void)
 
        if (!cancelled) {
                xen_arch_resume();
-               xenbus_resume();
+               xs_resume();
        } else
-               xenbus_suspend_cancel();
+               xs_suspend_cancel();
 
        device_power_up(PMSG_RESUME);
 
diff --git a/drivers/xen/sys-hypervisor.c b/drivers/xen/sys-hypervisor.c
new file mode 100644 (file)
index 0000000..88a60e0
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ *  copyright (c) 2006 IBM Corporation
+ *  Authored by: Mike D. Day <ncmike@us.ibm.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kobject.h>
+
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/xenbus.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/version.h>
+
+#define HYPERVISOR_ATTR_RO(_name) \
+static struct hyp_sysfs_attr  _name##_attr = __ATTR_RO(_name)
+
+#define HYPERVISOR_ATTR_RW(_name) \
+static struct hyp_sysfs_attr _name##_attr = \
+       __ATTR(_name, 0644, _name##_show, _name##_store)
+
+struct hyp_sysfs_attr {
+       struct attribute attr;
+       ssize_t (*show)(struct hyp_sysfs_attr *, char *);
+       ssize_t (*store)(struct hyp_sysfs_attr *, const char *, size_t);
+       void *hyp_attr_data;
+};
+
+static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer)
+{
+       return sprintf(buffer, "xen\n");
+}
+
+HYPERVISOR_ATTR_RO(type);
+
+static int __init xen_sysfs_type_init(void)
+{
+       return sysfs_create_file(hypervisor_kobj, &type_attr.attr);
+}
+
+static void xen_sysfs_type_destroy(void)
+{
+       sysfs_remove_file(hypervisor_kobj, &type_attr.attr);
+}
+
+/* xen version attributes */
+static ssize_t major_show(struct hyp_sysfs_attr *attr, char *buffer)
+{
+       int version = HYPERVISOR_xen_version(XENVER_version, NULL);
+       if (version)
+               return sprintf(buffer, "%d\n", version >> 16);
+       return -ENODEV;
+}
+
+HYPERVISOR_ATTR_RO(major);
+
+static ssize_t minor_show(struct hyp_sysfs_attr *attr, char *buffer)
+{
+       int version = HYPERVISOR_xen_version(XENVER_version, NULL);
+       if (version)
+               return sprintf(buffer, "%d\n", version & 0xff);
+       return -ENODEV;
+}
+
+HYPERVISOR_ATTR_RO(minor);
+
+static ssize_t extra_show(struct hyp_sysfs_attr *attr, char *buffer)
+{
+       int ret = -ENOMEM;
+       char *extra;
+
+       extra = kmalloc(XEN_EXTRAVERSION_LEN, GFP_KERNEL);
+       if (extra) {
+               ret = HYPERVISOR_xen_version(XENVER_extraversion, extra);
+               if (!ret)
+                       ret = sprintf(buffer, "%s\n", extra);
+               kfree(extra);
+       }
+
+       return ret;
+}
+
+HYPERVISOR_ATTR_RO(extra);
+
+static struct attribute *version_attrs[] = {
+       &major_attr.attr,
+       &minor_attr.attr,
+       &extra_attr.attr,
+       NULL
+};
+
+static struct attribute_group version_group = {
+       .name = "version",
+       .attrs = version_attrs,
+};
+
+static int __init xen_sysfs_version_init(void)
+{
+       return sysfs_create_group(hypervisor_kobj, &version_group);
+}
+
+static void xen_sysfs_version_destroy(void)
+{
+       sysfs_remove_group(hypervisor_kobj, &version_group);
+}
+
+/* UUID */
+
+static ssize_t uuid_show(struct hyp_sysfs_attr *attr, char *buffer)
+{
+       char *vm, *val;
+       int ret;
+       extern int xenstored_ready;
+
+       if (!xenstored_ready)
+               return -EBUSY;
+
+       vm = xenbus_read(XBT_NIL, "vm", "", NULL);
+       if (IS_ERR(vm))
+               return PTR_ERR(vm);
+       val = xenbus_read(XBT_NIL, vm, "uuid", NULL);
+       kfree(vm);
+       if (IS_ERR(val))
+               return PTR_ERR(val);
+       ret = sprintf(buffer, "%s\n", val);
+       kfree(val);
+       return ret;
+}
+
+HYPERVISOR_ATTR_RO(uuid);
+
+static int __init xen_sysfs_uuid_init(void)
+{
+       return sysfs_create_file(hypervisor_kobj, &uuid_attr.attr);
+}
+
+static void xen_sysfs_uuid_destroy(void)
+{
+       sysfs_remove_file(hypervisor_kobj, &uuid_attr.attr);
+}
+
+/* xen compilation attributes */
+
+static ssize_t compiler_show(struct hyp_sysfs_attr *attr, char *buffer)
+{
+       int ret = -ENOMEM;
+       struct xen_compile_info *info;
+
+       info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
+       if (info) {
+               ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
+               if (!ret)
+                       ret = sprintf(buffer, "%s\n", info->compiler);
+               kfree(info);
+       }
+
+       return ret;
+}
+
+HYPERVISOR_ATTR_RO(compiler);
+
+static ssize_t compiled_by_show(struct hyp_sysfs_attr *attr, char *buffer)
+{
+       int ret = -ENOMEM;
+       struct xen_compile_info *info;
+
+       info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
+       if (info) {
+               ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
+               if (!ret)
+                       ret = sprintf(buffer, "%s\n", info->compile_by);
+               kfree(info);
+       }
+
+       return ret;
+}
+
+HYPERVISOR_ATTR_RO(compiled_by);
+
+static ssize_t compile_date_show(struct hyp_sysfs_attr *attr, char *buffer)
+{
+       int ret = -ENOMEM;
+       struct xen_compile_info *info;
+
+       info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
+       if (info) {
+               ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
+               if (!ret)
+                       ret = sprintf(buffer, "%s\n", info->compile_date);
+               kfree(info);
+       }
+
+       return ret;
+}
+
+HYPERVISOR_ATTR_RO(compile_date);
+
+static struct attribute *xen_compile_attrs[] = {
+       &compiler_attr.attr,
+       &compiled_by_attr.attr,
+       &compile_date_attr.attr,
+       NULL
+};
+
+static struct attribute_group xen_compilation_group = {
+       .name = "compilation",
+       .attrs = xen_compile_attrs,
+};
+
+int __init static xen_compilation_init(void)
+{
+       return sysfs_create_group(hypervisor_kobj, &xen_compilation_group);
+}
+
+static void xen_compilation_destroy(void)
+{
+       sysfs_remove_group(hypervisor_kobj, &xen_compilation_group);
+}
+
+/* xen properties info */
+
+static ssize_t capabilities_show(struct hyp_sysfs_attr *attr, char *buffer)
+{
+       int ret = -ENOMEM;
+       char *caps;
+
+       caps = kmalloc(XEN_CAPABILITIES_INFO_LEN, GFP_KERNEL);
+       if (caps) {
+               ret = HYPERVISOR_xen_version(XENVER_capabilities, caps);
+               if (!ret)
+                       ret = sprintf(buffer, "%s\n", caps);
+               kfree(caps);
+       }
+
+       return ret;
+}
+
+HYPERVISOR_ATTR_RO(capabilities);
+
+static ssize_t changeset_show(struct hyp_sysfs_attr *attr, char *buffer)
+{
+       int ret = -ENOMEM;
+       char *cset;
+
+       cset = kmalloc(XEN_CHANGESET_INFO_LEN, GFP_KERNEL);
+       if (cset) {
+               ret = HYPERVISOR_xen_version(XENVER_changeset, cset);
+               if (!ret)
+                       ret = sprintf(buffer, "%s\n", cset);
+               kfree(cset);
+       }
+
+       return ret;
+}
+
+HYPERVISOR_ATTR_RO(changeset);
+
+static ssize_t virtual_start_show(struct hyp_sysfs_attr *attr, char *buffer)
+{
+       int ret = -ENOMEM;
+       struct xen_platform_parameters *parms;
+
+       parms = kmalloc(sizeof(struct xen_platform_parameters), GFP_KERNEL);
+       if (parms) {
+               ret = HYPERVISOR_xen_version(XENVER_platform_parameters,
+                                            parms);
+               if (!ret)
+                       ret = sprintf(buffer, "%lx\n", parms->virt_start);
+               kfree(parms);
+       }
+
+       return ret;
+}
+
+HYPERVISOR_ATTR_RO(virtual_start);
+
+static ssize_t pagesize_show(struct hyp_sysfs_attr *attr, char *buffer)
+{
+       int ret;
+
+       ret = HYPERVISOR_xen_version(XENVER_pagesize, NULL);
+       if (ret > 0)
+               ret = sprintf(buffer, "%x\n", ret);
+
+       return ret;
+}
+
+HYPERVISOR_ATTR_RO(pagesize);
+
+static ssize_t xen_feature_show(int index, char *buffer)
+{
+       ssize_t ret;
+       struct xen_feature_info info;
+
+       info.submap_idx = index;
+       ret = HYPERVISOR_xen_version(XENVER_get_features, &info);
+       if (!ret)
+               ret = sprintf(buffer, "%08x", info.submap);
+
+       return ret;
+}
+
+static ssize_t features_show(struct hyp_sysfs_attr *attr, char *buffer)
+{
+       ssize_t len;
+       int i;
+
+       len = 0;
+       for (i = XENFEAT_NR_SUBMAPS-1; i >= 0; i--) {
+               int ret = xen_feature_show(i, buffer + len);
+               if (ret < 0) {
+                       if (len == 0)
+                               len = ret;
+                       break;
+               }
+               len += ret;
+       }
+       if (len > 0)
+               buffer[len++] = '\n';
+
+       return len;
+}
+
+HYPERVISOR_ATTR_RO(features);
+
+static struct attribute *xen_properties_attrs[] = {
+       &capabilities_attr.attr,
+       &changeset_attr.attr,
+       &virtual_start_attr.attr,
+       &pagesize_attr.attr,
+       &features_attr.attr,
+       NULL
+};
+
+static struct attribute_group xen_properties_group = {
+       .name = "properties",
+       .attrs = xen_properties_attrs,
+};
+
+static int __init xen_properties_init(void)
+{
+       return sysfs_create_group(hypervisor_kobj, &xen_properties_group);
+}
+
+static void xen_properties_destroy(void)
+{
+       sysfs_remove_group(hypervisor_kobj, &xen_properties_group);
+}
+
+static int __init hyper_sysfs_init(void)
+{
+       int ret;
+
+       if (!xen_domain())
+               return -ENODEV;
+
+       ret = xen_sysfs_type_init();
+       if (ret)
+               goto out;
+       ret = xen_sysfs_version_init();
+       if (ret)
+               goto version_out;
+       ret = xen_compilation_init();
+       if (ret)
+               goto comp_out;
+       ret = xen_sysfs_uuid_init();
+       if (ret)
+               goto uuid_out;
+       ret = xen_properties_init();
+       if (ret)
+               goto prop_out;
+
+       goto out;
+
+prop_out:
+       xen_sysfs_uuid_destroy();
+uuid_out:
+       xen_compilation_destroy();
+comp_out:
+       xen_sysfs_version_destroy();
+version_out:
+       xen_sysfs_type_destroy();
+out:
+       return ret;
+}
+
+static void __exit hyper_sysfs_exit(void)
+{
+       xen_properties_destroy();
+       xen_compilation_destroy();
+       xen_sysfs_uuid_destroy();
+       xen_sysfs_version_destroy();
+       xen_sysfs_type_destroy();
+
+}
+module_init(hyper_sysfs_init);
+module_exit(hyper_sysfs_exit);
+
+static ssize_t hyp_sysfs_show(struct kobject *kobj,
+                             struct attribute *attr,
+                             char *buffer)
+{
+       struct hyp_sysfs_attr *hyp_attr;
+       hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr);
+       if (hyp_attr->show)
+               return hyp_attr->show(hyp_attr, buffer);
+       return 0;
+}
+
+static ssize_t hyp_sysfs_store(struct kobject *kobj,
+                              struct attribute *attr,
+                              const char *buffer,
+                              size_t len)
+{
+       struct hyp_sysfs_attr *hyp_attr;
+       hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr);
+       if (hyp_attr->store)
+               return hyp_attr->store(hyp_attr, buffer, len);
+       return 0;
+}
+
+static struct sysfs_ops hyp_sysfs_ops = {
+       .show = hyp_sysfs_show,
+       .store = hyp_sysfs_store,
+};
+
+static struct kobj_type hyp_sysfs_kobj_type = {
+       .sysfs_ops = &hyp_sysfs_ops,
+};
+
+static int __init hypervisor_subsys_init(void)
+{
+       if (!xen_domain())
+               return -ENODEV;
+
+       hypervisor_kobj->ktype = &hyp_sysfs_kobj_type;
+       return 0;
+}
+device_initcall(hypervisor_subsys_init);
index 773d1cf2328334b9c62cc52fdf90c7107df02778..d42e25d5968dcf48acd5448a7a6af56d21abd5fb 100644 (file)
@@ -71,6 +71,9 @@ static int xenbus_probe_frontend(const char *type, const char *name);
 
 static void xenbus_dev_shutdown(struct device *_dev);
 
+static int xenbus_dev_suspend(struct device *dev, pm_message_t state);
+static int xenbus_dev_resume(struct device *dev);
+
 /* If something in array of ids matches this device, return it. */
 static const struct xenbus_device_id *
 match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
@@ -188,6 +191,9 @@ static struct xen_bus_type xenbus_frontend = {
                .remove    = xenbus_dev_remove,
                .shutdown  = xenbus_dev_shutdown,
                .dev_attrs = xenbus_dev_attrs,
+
+               .suspend   = xenbus_dev_suspend,
+               .resume    = xenbus_dev_resume,
        },
 };
 
@@ -654,6 +660,7 @@ void xenbus_dev_changed(const char *node, struct xen_bus_type *bus)
 
        kfree(root);
 }
+EXPORT_SYMBOL_GPL(xenbus_dev_changed);
 
 static void frontend_changed(struct xenbus_watch *watch,
                             const char **vec, unsigned int len)
@@ -669,7 +676,7 @@ static struct xenbus_watch fe_watch = {
        .callback = frontend_changed,
 };
 
-static int suspend_dev(struct device *dev, void *data)
+static int xenbus_dev_suspend(struct device *dev, pm_message_t state)
 {
        int err = 0;
        struct xenbus_driver *drv;
@@ -682,35 +689,14 @@ static int suspend_dev(struct device *dev, void *data)
        drv = to_xenbus_driver(dev->driver);
        xdev = container_of(dev, struct xenbus_device, dev);
        if (drv->suspend)
-               err = drv->suspend(xdev);
+               err = drv->suspend(xdev, state);
        if (err)
                printk(KERN_WARNING
                       "xenbus: suspend %s failed: %i\n", dev_name(dev), err);
        return 0;
 }
 
-static int suspend_cancel_dev(struct device *dev, void *data)
-{
-       int err = 0;
-       struct xenbus_driver *drv;
-       struct xenbus_device *xdev;
-
-       DPRINTK("");
-
-       if (dev->driver == NULL)
-               return 0;
-       drv = to_xenbus_driver(dev->driver);
-       xdev = container_of(dev, struct xenbus_device, dev);
-       if (drv->suspend_cancel)
-               err = drv->suspend_cancel(xdev);
-       if (err)
-               printk(KERN_WARNING
-                      "xenbus: suspend_cancel %s failed: %i\n",
-                      dev_name(dev), err);
-       return 0;
-}
-
-static int resume_dev(struct device *dev, void *data)
+static int xenbus_dev_resume(struct device *dev)
 {
        int err;
        struct xenbus_driver *drv;
@@ -755,33 +741,6 @@ static int resume_dev(struct device *dev, void *data)
        return 0;
 }
 
-void xenbus_suspend(void)
-{
-       DPRINTK("");
-
-       bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
-       xenbus_backend_suspend(suspend_dev);
-       xs_suspend();
-}
-EXPORT_SYMBOL_GPL(xenbus_suspend);
-
-void xenbus_resume(void)
-{
-       xb_init_comms();
-       xs_resume();
-       bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
-       xenbus_backend_resume(resume_dev);
-}
-EXPORT_SYMBOL_GPL(xenbus_resume);
-
-void xenbus_suspend_cancel(void)
-{
-       xs_suspend_cancel();
-       bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_cancel_dev);
-       xenbus_backend_resume(suspend_cancel_dev);
-}
-EXPORT_SYMBOL_GPL(xenbus_suspend_cancel);
-
 /* A flag to determine if xenstored is 'ready' (i.e. has started) */
 int xenstored_ready = 0;
 
index e325eab4724d8cb0fab667b26f8c5b104c965c05..eab33f1dbdf7013f451af491b882973ea017f718 100644 (file)
@@ -673,6 +673,8 @@ void xs_resume(void)
        struct xenbus_watch *watch;
        char token[sizeof(watch) * 2 + 1];
 
+       xb_init_comms();
+
        mutex_unlock(&xs_state.response_mutex);
        mutex_unlock(&xs_state.request_mutex);
        up_write(&xs_state.transaction_mutex);
index 515741a8e6b8ecaae5bcd2d36af6538a2ee77345..6559e0c752ce1494baa127921834e388832cbd75 100644 (file)
 MODULE_DESCRIPTION("Xen filesystem");
 MODULE_LICENSE("GPL");
 
+static ssize_t capabilities_read(struct file *file, char __user *buf,
+                                size_t size, loff_t *off)
+{
+       char *tmp = "";
+
+       if (xen_initial_domain())
+               tmp = "control_d\n";
+
+       return simple_read_from_buffer(buf, size, off, tmp, strlen(tmp));
+}
+
+static const struct file_operations capabilities_file_ops = {
+       .read = capabilities_read,
+};
+
 static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
 {
        static struct tree_descr xenfs_files[] = {
-               [2] = {"xenbus", &xenbus_file_ops, S_IRUSR|S_IWUSR},
+               [1] = {},
+               { "xenbus", &xenbus_file_ops, S_IRUSR|S_IWUSR },
+               { "capabilities", &capabilities_file_ops, S_IRUGO },
                {""},
        };
 
index 98711647ece49548a94409a99ce4b680ee085ca1..59000215e59b695a2cefbe656d2be797bf86afaf 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
 #include <linux/mempool.h>
 #include <linux/workqueue.h>
 #include <linux/blktrace_api.h>
-#include <trace/block.h>
 #include <scsi/sg.h>           /* for struct sg_iovec */
 
-DEFINE_TRACE(block_split);
+#include <trace/events/block.h>
 
 /*
  * Test patch to inline a certain number of bi_io_vec's inside the bio
@@ -499,11 +498,11 @@ int bio_get_nr_vecs(struct block_device *bdev)
        struct request_queue *q = bdev_get_queue(bdev);
        int nr_pages;
 
-       nr_pages = ((q->max_sectors << 9) + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       if (nr_pages > q->max_phys_segments)
-               nr_pages = q->max_phys_segments;
-       if (nr_pages > q->max_hw_segments)
-               nr_pages = q->max_hw_segments;
+       nr_pages = ((queue_max_sectors(q) << 9) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       if (nr_pages > queue_max_phys_segments(q))
+               nr_pages = queue_max_phys_segments(q);
+       if (nr_pages > queue_max_hw_segments(q))
+               nr_pages = queue_max_hw_segments(q);
 
        return nr_pages;
 }
@@ -562,8 +561,8 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
         * make this too complex.
         */
 
-       while (bio->bi_phys_segments >= q->max_phys_segments
-              || bio->bi_phys_segments >= q->max_hw_segments) {
+       while (bio->bi_phys_segments >= queue_max_phys_segments(q)
+              || bio->bi_phys_segments >= queue_max_hw_segments(q)) {
 
                if (retried_segments)
                        return 0;
@@ -634,7 +633,8 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
 int bio_add_pc_page(struct request_queue *q, struct bio *bio, struct page *page,
                    unsigned int len, unsigned int offset)
 {
-       return __bio_add_page(q, bio, page, len, offset, q->max_hw_sectors);
+       return __bio_add_page(q, bio, page, len, offset,
+                             queue_max_hw_sectors(q));
 }
 
 /**
@@ -654,7 +654,7 @@ int bio_add_page(struct bio *bio, struct page *page, unsigned int len,
                 unsigned int offset)
 {
        struct request_queue *q = bdev_get_queue(bio->bi_bdev);
-       return __bio_add_page(q, bio, page, len, offset, q->max_sectors);
+       return __bio_add_page(q, bio, page, len, offset, queue_max_sectors(q));
 }
 
 struct bio_map_data {
@@ -721,7 +721,7 @@ static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs,
 
                while (bv_len && iov_idx < iov_count) {
                        unsigned int bytes;
-                       char *iov_addr;
+                       char __user *iov_addr;
 
                        bytes = min_t(unsigned int,
                                      iov[iov_idx].iov_len - iov_off, bv_len);
@@ -1201,7 +1201,7 @@ static void bio_copy_kern_endio(struct bio *bio, int err)
                char *addr = page_address(bvec->bv_page);
                int len = bmd->iovecs[i].bv_len;
 
-               if (read && !err)
+               if (read)
                        memcpy(p, addr, len);
 
                __free_page(bvec->bv_page);
@@ -1490,11 +1490,12 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors)
 sector_t bio_sector_offset(struct bio *bio, unsigned short index,
                           unsigned int offset)
 {
-       unsigned int sector_sz = queue_hardsect_size(bio->bi_bdev->bd_disk->queue);
+       unsigned int sector_sz;
        struct bio_vec *bv;
        sector_t sectors;
        int i;
 
+       sector_sz = queue_logical_block_size(bio->bi_bdev->bd_disk->queue);
        sectors = 0;
 
        if (index >= bio->bi_idx)
index f45dbc18dd175891950ddb84fffa2bc6ce0df117..2dfc6cdcebbe03a3c4ac76480771a9eac94ae27f 100644 (file)
@@ -76,7 +76,7 @@ int set_blocksize(struct block_device *bdev, int size)
                return -EINVAL;
 
        /* Size cannot be smaller than the size supported by the device */
-       if (size < bdev_hardsect_size(bdev))
+       if (size < bdev_logical_block_size(bdev))
                return -EINVAL;
 
        /* Don't change the size if it is same as current */
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(sb_set_blocksize);
 
 int sb_min_blocksize(struct super_block *sb, int size)
 {
-       int minsize = bdev_hardsect_size(sb->s_bdev);
+       int minsize = bdev_logical_block_size(sb->s_bdev);
        if (size < minsize)
                size = minsize;
        return sb_set_blocksize(sb, size);
@@ -1111,7 +1111,7 @@ EXPORT_SYMBOL(check_disk_change);
 
 void bd_set_size(struct block_device *bdev, loff_t size)
 {
-       unsigned bsize = bdev_hardsect_size(bdev);
+       unsigned bsize = bdev_logical_block_size(bdev);
 
        bdev->bd_inode->i_size = size;
        while (bsize < PAGE_CACHE_SIZE) {
index 49106127a4aa5f8f480dbd61968c0c6d0acd6b58..a3ef091a45bd4664e5ba5e683f9329bda3d1d3df 100644 (file)
@@ -1085,12 +1085,12 @@ static struct buffer_head *
 __getblk_slow(struct block_device *bdev, sector_t block, int size)
 {
        /* Size must be multiple of hard sectorsize */
-       if (unlikely(size & (bdev_hardsect_size(bdev)-1) ||
+       if (unlikely(size & (bdev_logical_block_size(bdev)-1) ||
                        (size < 512 || size > PAGE_SIZE))) {
                printk(KERN_ERR "getblk(): invalid block size %d requested\n",
                                        size);
-               printk(KERN_ERR "hardsect size: %d\n",
-                                       bdev_hardsect_size(bdev));
+               printk(KERN_ERR "logical block size: %d\n",
+                                       bdev_logical_block_size(bdev));
 
                dump_stack();
                return NULL;
@@ -2935,6 +2935,8 @@ int submit_bh(int rw, struct buffer_head * bh)
        BUG_ON(!buffer_locked(bh));
        BUG_ON(!buffer_mapped(bh));
        BUG_ON(!bh->b_end_io);
+       BUG_ON(buffer_delay(bh));
+       BUG_ON(buffer_unwritten(bh));
 
        /*
         * Mask in barrier bit for a write (could be either a WRITE or a
index f20c4069c22005681bc851bdc270f54c8a2475c1..b48689839428805efd6175eacd0a7396068cdafe 100644 (file)
@@ -1,3 +1,12 @@
+Version 1.59
+------------
+Client uses server inode numbers (which are persistent) rather than
+client generated ones by default (mount option "serverino" turned
+on by default if server supports it).  Add forceuid and forcegid
+mount options (so that when negotiating unix extensions specifying
+which uid mounted does not immediately force the server's reported
+uids to be overridden).
+
 Version 1.58
 ------------
 Guard against buffer overruns in various UCS-2 to UTF-8 string conversions
@@ -10,6 +19,8 @@ we converted from).  Fix endianness of the vcnum field used during
 session setup to distinguish multiple mounts to same server from different
 userids. Raw NTLMSSP fixed (it requires /proc/fs/cifs/experimental
 flag to be set to 2, and mount must enable krb5 to turn on extended security).
+Performance of file create to Samba improved (posix create on lookup
+removes 1 of 2 network requests sent on file create)
  
 Version 1.57
 ------------
index db208ddb989910d469f958054d000558c528a8d7..ad92921dbde415b7a00d0c063d6ca9adfb0d582d 100644 (file)
@@ -262,7 +262,8 @@ A partial list of the supported mount options follows:
                mount.  
   domain       Set the SMB/CIFS workgroup name prepended to the
                username during CIFS session establishment
-  uid          Set the default uid for inodes. For mounts to servers
+  forceuid     Set the default uid for inodes based on the uid
+               passed in. For mounts to servers
                which do support the CIFS Unix extensions, such as a
                properly configured Samba server, the server provides
                the uid, gid and mode so this parameter should  not be
@@ -292,6 +293,12 @@ A partial list of the supported mount options follows:
                the client.  Note that the mount.cifs helper must be
                at version 1.10 or higher to support specifying the uid
                (or gid) in non-numeric form.
+  forcegid     (similar to above but for the groupid instead of uid)
+  uid          Set the default uid for inodes, and indicate to the
+               cifs kernel driver which local user mounted . If the server
+               supports the unix extensions the default uid is
+               not used to fill in the owner fields of inodes (files)
+               unless the "forceuid" parameter is specified.
   gid          Set the default gid for inodes (similar to above).
   file_mode     If CIFS Unix extensions are not supported by the server
                this overrides the default mode for file inodes.
@@ -388,8 +395,13 @@ A partial list of the supported mount options follows:
                or the CIFS Unix Extensions equivalent and for those
                this mount option will have no effect.  Exporting cifs mounts
                under nfsd requires this mount option on the cifs mount.
+               This is now the default if server supports the 
+               required network operation.
   noserverino   Client generates inode numbers (rather than using the actual one
-               from the server) by default.
+               from the server). These inode numbers will vary after
+               unmount or reboot which can confuse some applications,
+               but not all server filesystems support unique inode
+               numbers.
   setuids       If the CIFS Unix extensions are negotiated with the server
                the client will attempt to set the effective uid and gid of
                the local process on newly created files, directories, and
index 67bf93a40d2eeb46a42175183810c25c3cd1db58..4a4581cb2b5e3442e1cc0da0f0a7cd2f6de930bd 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/string.h>
 #include <keys/user-type.h>
 #include <linux/key-type.h>
+#include <linux/inet.h>
 #include "cifsglob.h"
 #include "cifs_spnego.h"
 #include "cifs_debug.h"
@@ -73,9 +74,6 @@ struct key_type cifs_spnego_key_type = {
  * strlen(";sec=ntlmsspi") */
 #define MAX_MECH_STR_LEN       13
 
-/* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/128 */
-#define MAX_IPV6_ADDR_LEN      43
-
 /* strlen of "host=" */
 #define HOST_KEY_LEN           5
 
@@ -102,7 +100,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
           host=hostname sec=mechanism uid=0xFF user=username */
        desc_len = MAX_VER_STR_LEN +
                   HOST_KEY_LEN + strlen(hostname) +
-                  IP_KEY_LEN + MAX_IPV6_ADDR_LEN +
+                  IP_KEY_LEN + INET6_ADDRSTRLEN +
                   MAX_MECH_STR_LEN +
                   UID_KEY_LEN + (sizeof(uid_t) * 2) +
                   USER_KEY_LEN + strlen(sesInfo->userName) + 1;
index 57ecdc83c26f3852440e67957ca031577cba8543..1403b5d86a739d67725e0dc94db1bec593e5ddab 100644 (file)
@@ -552,130 +552,138 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
        return rc;
 }
 
-
-/* Retrieve an ACL from the server */
-static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
-                                      const char *path, const __u16 *pfid)
+static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
+               __u16 fid, u32 *pacllen)
 {
-       struct cifsFileInfo *open_file = NULL;
-       bool unlock_file = false;
-       int xid;
-       int rc = -EIO;
-       __u16 fid;
-       struct super_block *sb;
-       struct cifs_sb_info *cifs_sb;
        struct cifs_ntsd *pntsd = NULL;
+       int xid, rc;
+
+       xid = GetXid();
+       rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
+       FreeXid(xid);
 
-       cFYI(1, ("get mode from ACL for %s", path));
 
-       if (inode == NULL)
-               return NULL;
+       cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen));
+       return pntsd;
+}
+
+static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
+               const char *path, u32 *pacllen)
+{
+       struct cifs_ntsd *pntsd = NULL;
+       int oplock = 0;
+       int xid, rc;
+       __u16 fid;
 
        xid = GetXid();
-       if (pfid == NULL)
-               open_file = find_readable_file(CIFS_I(inode));
-       else
-               fid = *pfid;
 
-       sb = inode->i_sb;
-       if (sb == NULL) {
-               FreeXid(xid);
-               return NULL;
-       }
-       cifs_sb = CIFS_SB(sb);
-
-       if (open_file) {
-               unlock_file = true;
-               fid = open_file->netfid;
-       } else if (pfid == NULL) {
-               int oplock = 0;
-               /* open file */
-               rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
-                               READ_CONTROL, 0, &fid, &oplock, NULL,
-                               cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
-               if (rc != 0) {
-                       cERROR(1, ("Unable to open file to get ACL"));
-                       FreeXid(xid);
-                       return NULL;
-               }
+       rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, READ_CONTROL, 0,
+                        &fid, &oplock, NULL, cifs_sb->local_nls,
+                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       if (rc) {
+               cERROR(1, ("Unable to open file to get ACL"));
+               goto out;
        }
 
        rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
        cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen));
-       if (unlock_file == true) /* find_readable_file increments ref count */
-               atomic_dec(&open_file->wrtPending);
-       else if (pfid == NULL) /* if opened above we have to close the handle */
-               CIFSSMBClose(xid, cifs_sb->tcon, fid);
-       /* else handle was passed in by caller */
 
+       CIFSSMBClose(xid, cifs_sb->tcon, fid);
+ out:
        FreeXid(xid);
        return pntsd;
 }
 
-/* Set an ACL on the server */
-static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
-                               struct inode *inode, const char *path)
+/* Retrieve an ACL from the server */
+static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
+                                     struct inode *inode, const char *path,
+                                     u32 *pacllen)
 {
-       struct cifsFileInfo *open_file;
-       bool unlock_file = false;
-       int xid;
-       int rc = -EIO;
-       __u16 fid;
-       struct super_block *sb;
-       struct cifs_sb_info *cifs_sb;
+       struct cifs_ntsd *pntsd = NULL;
+       struct cifsFileInfo *open_file = NULL;
 
-       cFYI(DBG2, ("set ACL for %s from mode 0x%x", path, inode->i_mode));
+       if (inode)
+               open_file = find_readable_file(CIFS_I(inode));
+       if (!open_file)
+               return get_cifs_acl_by_path(cifs_sb, path, pacllen);
 
-       if (!inode)
-               return rc;
+       pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
+       atomic_dec(&open_file->wrtPending);
+       return pntsd;
+}
 
-       sb = inode->i_sb;
-       if (sb == NULL)
-               return rc;
+static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
+               struct cifs_ntsd *pnntsd, u32 acllen)
+{
+       int xid, rc;
 
-       cifs_sb = CIFS_SB(sb);
        xid = GetXid();
+       rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
+       FreeXid(xid);
 
-       open_file = find_readable_file(CIFS_I(inode));
-       if (open_file) {
-               unlock_file = true;
-               fid = open_file->netfid;
-       } else {
-               int oplock = 0;
-               /* open file */
-               rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
-                               WRITE_DAC, 0, &fid, &oplock, NULL,
-                               cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
-               if (rc != 0) {
-                       cERROR(1, ("Unable to open file to set ACL"));
-                       FreeXid(xid);
-                       return rc;
-               }
+       cFYI(DBG2, ("SetCIFSACL rc = %d", rc));
+       return rc;
+}
+
+static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
+               struct cifs_ntsd *pnntsd, u32 acllen)
+{
+       int oplock = 0;
+       int xid, rc;
+       __u16 fid;
+
+       xid = GetXid();
+
+       rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, WRITE_DAC, 0,
+                        &fid, &oplock, NULL, cifs_sb->local_nls,
+                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       if (rc) {
+               cERROR(1, ("Unable to open file to set ACL"));
+               goto out;
        }
 
        rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
        cFYI(DBG2, ("SetCIFSACL rc = %d", rc));
-       if (unlock_file)
-               atomic_dec(&open_file->wrtPending);
-       else
-               CIFSSMBClose(xid, cifs_sb->tcon, fid);
 
+       CIFSSMBClose(xid, cifs_sb->tcon, fid);
+ out:
        FreeXid(xid);
+       return rc;
+}
 
+/* Set an ACL on the server */
+static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
+                               struct inode *inode, const char *path)
+{
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       struct cifsFileInfo *open_file;
+       int rc;
+
+       cFYI(DBG2, ("set ACL for %s from mode 0x%x", path, inode->i_mode));
+
+       open_file = find_readable_file(CIFS_I(inode));
+       if (!open_file)
+               return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
+
+       rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
+       atomic_dec(&open_file->wrtPending);
        return rc;
 }
 
 /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
-void acl_to_uid_mode(struct inode *inode, const char *path, const __u16 *pfid)
+void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
+                    const char *path, const __u16 *pfid)
 {
        struct cifs_ntsd *pntsd = NULL;
        u32 acllen = 0;
        int rc = 0;
 
        cFYI(DBG2, ("converting ACL to mode for %s", path));
-       pntsd = get_cifs_acl(&acllen, inode, path, pfid);
+
+       if (pfid)
+               pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
+       else
+               pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
 
        /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
        if (pntsd)
@@ -698,7 +706,7 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
        cFYI(DBG2, ("set ACL from mode for %s", path));
 
        /* Get the security descriptor */
-       pntsd = get_cifs_acl(&secdesclen, inode, path, NULL);
+       pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
 
        /* Add three ACEs for owner, group, everyone getting rid of
           other ACEs as chmod disables ACEs and set the security descriptor */
index 5e6d35804d73511162230f67626aeaf331333982..0a10a59b6392891e4f0f319d6fa6cf62ec4d0cbd 100644 (file)
@@ -146,7 +146,7 @@ cifs_read_super(struct super_block *sb, void *data,
 #endif
        sb->s_blocksize = CIFS_MAX_MSGSIZE;
        sb->s_blocksize_bits = 14;      /* default 2**14 = CIFS_MAX_MSGSIZE */
-       inode = cifs_iget(sb, ROOT_I);
+       inode = cifs_root_iget(sb, ROOT_I);
 
        if (IS_ERR(inode)) {
                rc = PTR_ERR(inode);
index 051b71cfdea9b9725b12026fd6aec17325da26fd..9570a0e8023f4258941d1f4cdc0e8141188a622d 100644 (file)
@@ -36,7 +36,7 @@ extern void cifs_read_inode(struct inode *);
 
 /* Functions related to inodes */
 extern const struct inode_operations cifs_dir_inode_ops;
-extern struct inode *cifs_iget(struct super_block *, unsigned long);
+extern struct inode *cifs_root_iget(struct super_block *, unsigned long);
 extern int cifs_create(struct inode *, struct dentry *, int,
                       struct nameidata *);
 extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
@@ -100,5 +100,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* EXPERIMENTAL */
 
-#define CIFS_VERSION   "1.58"
+#define CIFS_VERSION   "1.59"
 #endif                         /* _CIFSFS_H */
index fae083930eee2210d1ae3e950c7d1639e1c9505e..f9452329bcce5b02929c5090a79220170d329813 100644 (file)
@@ -90,10 +90,10 @@ extern struct oplock_q_entry *AllocOplockQEntry(struct inode *, u16,
                                                 struct cifsTconInfo *);
 extern void DeleteOplockQEntry(struct oplock_q_entry *);
 extern void DeleteTconOplockQEntries(struct cifsTconInfo *);
-extern struct timespec cifs_NTtimeToUnix(u64 utc_nanoseconds_since_1601);
+extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
 extern u64 cifs_UnixTimeToNT(struct timespec);
-extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
-extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
+extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
+                                     int offset);
 
 extern int cifs_posix_open(char *full_path, struct inode **pinode,
                           struct super_block *sb, int mode, int oflags,
@@ -108,8 +108,8 @@ extern int cifs_get_inode_info(struct inode **pinode,
 extern int cifs_get_inode_info_unix(struct inode **pinode,
                        const unsigned char *search_path,
                        struct super_block *sb, int xid);
-extern void acl_to_uid_mode(struct inode *inode, const char *path,
-                           const __u16 *pfid);
+extern void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
+                           const char *path, const __u16 *pfid);
 extern int mode_to_acl(struct inode *inode, const char *path, __u64);
 
 extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
index d06260251c304692dc2789c14059170245ad2957..b84c61d5bca419d2ea221484636508f1ddaceaa1 100644 (file)
@@ -524,8 +524,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                        int val, seconds, remain, result;
                        struct timespec ts, utc;
                        utc = CURRENT_TIME;
-                       ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
-                                               le16_to_cpu(rsp->SrvTime.Time));
+                       ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
+                                           rsp->SrvTime.Time, 0);
                        cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
                                (int)ts.tv_sec, (int)utc.tv_sec,
                                (int)(utc.tv_sec - ts.tv_sec)));
@@ -2427,8 +2427,7 @@ querySymLinkRetry:
        params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       /* BB find exact max data count below from sess structure BB */
-       pSMB->MaxDataCount = cpu_to_le16(4000);
+       pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
index 4aa81a507b741110657eeb1e7899235296d829d8..97f4311b9a8ea2f40325ac2fda8a2929153402eb 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/namei.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
+#include <linux/inet.h>
 #include <net/ipv6.h>
 #include "cifspdu.h"
 #include "cifsglob.h"
@@ -61,7 +62,6 @@ struct smb_vol {
        char *domainname;
        char *UNC;
        char *UNCip;
-       char *in6_addr;   /* ipv6 address as human readable form of in6_addr */
        char *iocharset;  /* local code page for mapping to and from Unicode */
        char source_rfc1001_name[16]; /* netbios name of client */
        char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
@@ -827,14 +827,16 @@ cifs_parse_mount_options(char *options, const char *devname,
        vol->target_rfc1001_name[0] = 0;
        vol->linux_uid = current_uid();  /* use current_euid() instead? */
        vol->linux_gid = current_gid();
-       vol->dir_mode = S_IRWXUGO;
-       /* 2767 perms indicate mandatory locking support */
-       vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
+
+       /* default to only allowing write access to owner of the mount */
+       vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
 
        /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
        vol->rw = true;
        /* default is always to request posix paths. */
        vol->posix_paths = 1;
+       /* default to using server inode numbers where available */
+       vol->server_ino = 1;
 
        if (!options)
                return 1;
@@ -955,10 +957,12 @@ cifs_parse_mount_options(char *options, const char *devname,
                                }
                                strcpy(vol->password, value);
                        }
-               } else if (strnicmp(data, "ip", 2) == 0) {
+               } else if (!strnicmp(data, "ip", 2) ||
+                          !strnicmp(data, "addr", 4)) {
                        if (!value || !*value) {
                                vol->UNCip = NULL;
-                       } else if (strnlen(value, 35) < 35) {
+                       } else if (strnlen(value, INET6_ADDRSTRLEN) <
+                                                       INET6_ADDRSTRLEN) {
                                vol->UNCip = value;
                        } else {
                                printk(KERN_WARNING "CIFS: ip address "
@@ -1092,17 +1096,17 @@ cifs_parse_mount_options(char *options, const char *devname,
                                return 1;
                        }
                } else if (strnicmp(data, "uid", 3) == 0) {
-                       if (value && *value) {
+                       if (value && *value)
                                vol->linux_uid =
                                        simple_strtoul(value, &value, 0);
+               } else if (strnicmp(data, "forceuid", 8) == 0) {
                                vol->override_uid = 1;
-                       }
                } else if (strnicmp(data, "gid", 3) == 0) {
-                       if (value && *value) {
+                       if (value && *value)
                                vol->linux_gid =
                                        simple_strtoul(value, &value, 0);
+               } else if (strnicmp(data, "forcegid", 8) == 0) {
                                vol->override_gid = 1;
-                       }
                } else if (strnicmp(data, "file_mode", 4) == 0) {
                        if (value && *value) {
                                vol->file_mode =
@@ -1315,16 +1319,6 @@ cifs_parse_mount_options(char *options, const char *devname,
                        vol->direct_io = 1;
                } else if (strnicmp(data, "forcedirectio", 13) == 0) {
                        vol->direct_io = 1;
-               } else if (strnicmp(data, "in6_addr", 8) == 0) {
-                       if (!value || !*value) {
-                               vol->in6_addr = NULL;
-                       } else if (strnlen(value, 49) == 48) {
-                               vol->in6_addr = value;
-                       } else {
-                               printk(KERN_WARNING "CIFS: ip v6 address not "
-                                                   "48 characters long\n");
-                               return 1;
-                       }
                } else if (strnicmp(data, "noac", 4) == 0) {
                        printk(KERN_WARNING "CIFS: Mount option noac not "
                                "supported. Instead set "
index 302ea15f02e611fb2d254e68740cb8e1cbdd81c2..06866841b97f1b9993ea3dd577f3f4478d06880e 100644 (file)
@@ -241,7 +241,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
        /* BB need same check in cifs_create too? */
        /* if not oplocked, invalidate inode pages if mtime or file
           size changed */
-       temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
+       temp = cifs_NTtimeToUnix(buf->LastWriteTime);
        if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
                           (file->f_path.dentry->d_inode->i_size ==
                            (loff_t)le64_to_cpu(buf->EndOfFile))) {
index 9c869a6dcba18cb496085625386922d8521ef513..fad882b075ba50358b113e58808b9845f6baca4c 100644 (file)
@@ -85,10 +85,10 @@ static void cifs_unix_info_to_inode(struct inode *inode,
        __u64 num_of_bytes = le64_to_cpu(info->NumOfBytes);
        __u64 end_of_file = le64_to_cpu(info->EndOfFile);
 
-       inode->i_atime = cifs_NTtimeToUnix(le64_to_cpu(info->LastAccessTime));
+       inode->i_atime = cifs_NTtimeToUnix(info->LastAccessTime);
        inode->i_mtime =
-               cifs_NTtimeToUnix(le64_to_cpu(info->LastModificationTime));
-       inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(info->LastStatusChange));
+               cifs_NTtimeToUnix(info->LastModificationTime);
+       inode->i_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
        inode->i_mode = le64_to_cpu(info->Permissions);
 
        /*
@@ -554,14 +554,11 @@ int cifs_get_inode_info(struct inode **pinode,
 
        /* Linux can not store file creation time so ignore it */
        if (pfindData->LastAccessTime)
-               inode->i_atime = cifs_NTtimeToUnix
-                       (le64_to_cpu(pfindData->LastAccessTime));
+               inode->i_atime = cifs_NTtimeToUnix(pfindData->LastAccessTime);
        else /* do not need to use current_fs_time - time not stored */
                inode->i_atime = CURRENT_TIME;
-       inode->i_mtime =
-                   cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
-       inode->i_ctime =
-           cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
+       inode->i_mtime = cifs_NTtimeToUnix(pfindData->LastWriteTime);
+       inode->i_ctime = cifs_NTtimeToUnix(pfindData->ChangeTime);
        cFYI(DBG2, ("Attributes came in as 0x%x", attr));
        if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
                inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
@@ -629,7 +626,7 @@ int cifs_get_inode_info(struct inode **pinode,
        /* fill in 0777 bits from ACL */
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
                cFYI(1, ("Getting mode bits from ACL"));
-               acl_to_uid_mode(inode, full_path, pfid);
+               acl_to_uid_mode(cifs_sb, inode, full_path, pfid);
        }
 #endif
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
@@ -699,7 +696,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
 }
 
 /* gets root inode */
-struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
+struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
 {
        int xid;
        struct cifs_sb_info *cifs_sb;
index e2fe998989a381ddc8625fde5334fae628f1dacd..32d6baa0a54fa907963d976c56d75c09d301e055 100644 (file)
@@ -853,12 +853,12 @@ smbCalcSize_LE(struct smb_hdr *ptr)
 
 #define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000)
 
-    /*
    * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units)
    * into Unix UTC (based 1970-01-01, in seconds).
    */
+/*
+ * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units)
+ * into Unix UTC (based 1970-01-01, in seconds).
+ */
 struct timespec
-cifs_NTtimeToUnix(u64 ntutc)
+cifs_NTtimeToUnix(__le64 ntutc)
 {
        struct timespec ts;
        /* BB what about the timezone? BB */
@@ -866,7 +866,7 @@ cifs_NTtimeToUnix(u64 ntutc)
        /* Subtract the NTFS time offset, then convert to 1s intervals. */
        u64 t;
 
-       t = ntutc - NTFS_TIME_OFFSET;
+       t = le64_to_cpu(ntutc) - NTFS_TIME_OFFSET;
        ts.tv_nsec = do_div(t, 10000000) * 100;
        ts.tv_sec = t;
        return ts;
@@ -883,16 +883,12 @@ cifs_UnixTimeToNT(struct timespec t)
 static int total_days_of_prev_months[] =
 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
 
-
-__le64 cnvrtDosCifsTm(__u16 date, __u16 time)
-{
-       return cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(date, time)));
-}
-
-struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
+struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset)
 {
        struct timespec ts;
        int sec, min, days, month, year;
+       u16 date = le16_to_cpu(le_date);
+       u16 time = le16_to_cpu(le_time);
        SMB_TIME *st = (SMB_TIME *)&time;
        SMB_DATE *sd = (SMB_DATE *)&date;
 
@@ -933,7 +929,7 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
                days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0);
        sec += 24 * 60 * 60 * days;
 
-       ts.tv_sec = sec;
+       ts.tv_sec = sec + offset;
 
        /* cFYI(1,("sec after cnvrt dos to unix time %d",sec)); */
 
index 964e097c82035b75f865275f3f7c6b45b3c69a63..86d0055dc529906df58a3dfddbc4b5601af08d0f 100644 (file)
@@ -115,17 +115,6 @@ construct_dentry(struct qstr *qstring, struct file *file,
        return rc;
 }
 
-static void AdjustForTZ(struct cifsTconInfo *tcon, struct inode *inode)
-{
-       if ((tcon) && (tcon->ses) && (tcon->ses->server)) {
-               inode->i_ctime.tv_sec += tcon->ses->server->timeAdj;
-               inode->i_mtime.tv_sec += tcon->ses->server->timeAdj;
-               inode->i_atime.tv_sec += tcon->ses->server->timeAdj;
-       }
-       return;
-}
-
-
 static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
                          char *buf, unsigned int *pobject_type, int isNewInode)
 {
@@ -150,26 +139,25 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
                allocation_size = le64_to_cpu(pfindData->AllocationSize);
                end_of_file = le64_to_cpu(pfindData->EndOfFile);
                tmp_inode->i_atime =
-                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
+                       cifs_NTtimeToUnix(pfindData->LastAccessTime);
                tmp_inode->i_mtime =
-                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
+                       cifs_NTtimeToUnix(pfindData->LastWriteTime);
                tmp_inode->i_ctime =
-                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
+                       cifs_NTtimeToUnix(pfindData->ChangeTime);
        } else { /* legacy, OS2 and DOS style */
-/*             struct timespec ts;*/
+               int offset = cifs_sb->tcon->ses->server->timeAdj;
                FIND_FILE_STANDARD_INFO *pfindData =
                        (FIND_FILE_STANDARD_INFO *)buf;
 
-               tmp_inode->i_mtime = cnvrtDosUnixTm(
-                               le16_to_cpu(pfindData->LastWriteDate),
-                               le16_to_cpu(pfindData->LastWriteTime));
-               tmp_inode->i_atime = cnvrtDosUnixTm(
-                               le16_to_cpu(pfindData->LastAccessDate),
-                               le16_to_cpu(pfindData->LastAccessTime));
-               tmp_inode->i_ctime = cnvrtDosUnixTm(
-                               le16_to_cpu(pfindData->LastWriteDate),
-                               le16_to_cpu(pfindData->LastWriteTime));
-               AdjustForTZ(cifs_sb->tcon, tmp_inode);
+               tmp_inode->i_mtime = cnvrtDosUnixTm(pfindData->LastWriteDate,
+                                                   pfindData->LastWriteTime,
+                                                   offset);
+               tmp_inode->i_atime = cnvrtDosUnixTm(pfindData->LastAccessDate,
+                                                   pfindData->LastAccessTime,
+                                                   offset);
+               tmp_inode->i_ctime = cnvrtDosUnixTm(pfindData->LastWriteDate,
+                                                   pfindData->LastWriteTime,
+                                                   offset);
                attr = le16_to_cpu(pfindData->Attributes);
                allocation_size = le32_to_cpu(pfindData->AllocationSize);
                end_of_file = le32_to_cpu(pfindData->DataSize);
@@ -331,11 +319,11 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
        local_size  = tmp_inode->i_size;
 
        tmp_inode->i_atime =
-           cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
+           cifs_NTtimeToUnix(pfindData->LastAccessTime);
        tmp_inode->i_mtime =
-           cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime));
+           cifs_NTtimeToUnix(pfindData->LastModificationTime);
        tmp_inode->i_ctime =
-           cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange));
+           cifs_NTtimeToUnix(pfindData->LastStatusChange);
 
        tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
        /* since we set the inode type below we need to mask off type
index 6a347fbc998a4cc3a23f60d3d2e91854db4206b2..ffd42815fda1e6a528030c13712a5c7455e28f21 100644 (file)
@@ -47,6 +47,8 @@ coda_file_splice_read(struct file *coda_file, loff_t *ppos,
                      struct pipe_inode_info *pipe, size_t count,
                      unsigned int flags)
 {
+       ssize_t (*splice_read)(struct file *, loff_t *,
+                              struct pipe_inode_info *, size_t, unsigned int);
        struct coda_file_info *cfi;
        struct file *host_file;
 
@@ -54,10 +56,11 @@ coda_file_splice_read(struct file *coda_file, loff_t *ppos,
        BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
        host_file = cfi->cfi_container;
 
-       if (!host_file->f_op || !host_file->f_op->splice_read)
-               return -EINVAL;
+       splice_read = host_file->f_op->splice_read;
+       if (!splice_read)
+               splice_read = default_file_splice_read;
 
-       return host_file->f_op->splice_read(host_file, ppos, pipe, count,flags);
+       return splice_read(host_file, ppos, pipe, count, flags);
 }
 
 static ssize_t
index 681ed81e6be03a44d4d6722441513c9b0fac621e..bb2a9b2e81738819491a7ae23e0c66be36abc39f 100644 (file)
@@ -1488,7 +1488,7 @@ int compat_do_execve(char * filename,
        if (!bprm)
                goto out_files;
 
-       retval = mutex_lock_interruptible(&current->cred_exec_mutex);
+       retval = mutex_lock_interruptible(&current->cred_guard_mutex);
        if (retval < 0)
                goto out_free;
        current->in_execve = 1;
@@ -1550,7 +1550,7 @@ int compat_do_execve(char * filename,
        /* execve succeeded */
        current->fs->in_exec = 0;
        current->in_execve = 0;
-       mutex_unlock(&current->cred_exec_mutex);
+       mutex_unlock(&current->cred_guard_mutex);
        acct_update_integrals(current);
        free_bprm(bprm);
        if (displaced)
@@ -1573,7 +1573,7 @@ out_unmark:
 
 out_unlock:
        current->in_execve = 0;
-       mutex_unlock(&current->cred_exec_mutex);
+       mutex_unlock(&current->cred_guard_mutex);
 
 out_free:
        free_bprm(bprm);
index c68edb969441c2f199c5b1475ec755ebdbc0fe62..9b1d285f9fe6eb069c9fc62d02beea8df018cffc 100644 (file)
@@ -557,8 +557,10 @@ static int __init init_devpts_fs(void)
        int err = register_filesystem(&devpts_fs_type);
        if (!err) {
                devpts_mnt = kern_mount(&devpts_fs_type);
-               if (IS_ERR(devpts_mnt))
+               if (IS_ERR(devpts_mnt)) {
                        err = PTR_ERR(devpts_mnt);
+                       unregister_filesystem(&devpts_fs_type);
+               }
        }
        return err;
 }
index 05763bbc2050b8ed917d593275b6ba37d1e8282b..8b10b87dc01a294845aac2afd1a2d22ae5a269b2 100644 (file)
@@ -1127,7 +1127,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
                rw = WRITE_ODIRECT;
 
        if (bdev)
-               bdev_blkbits = blksize_bits(bdev_hardsect_size(bdev));
+               bdev_blkbits = blksize_bits(bdev_logical_block_size(bdev));
 
        if (offset & blocksize_mask) {
                if (bdev)
index 895823d0149d9cfbd75bb34b670662dafb7f9ef6..a7fcd975c6b264d534f63f7958cc8918027010ae 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1016,7 +1016,7 @@ void install_exec_creds(struct linux_binprm *bprm)
        commit_creds(bprm->cred);
        bprm->cred = NULL;
 
-       /* cred_exec_mutex must be held at least to this point to prevent
+       /* cred_guard_mutex must be held at least to this point to prevent
         * ptrace_attach() from altering our determination of the task's
         * credentials; any time after this it may be unlocked */
 
@@ -1026,7 +1026,7 @@ EXPORT_SYMBOL(install_exec_creds);
 
 /*
  * determine how safe it is to execute the proposed program
- * - the caller must hold current->cred_exec_mutex to protect against
+ * - the caller must hold current->cred_guard_mutex to protect against
  *   PTRACE_ATTACH
  */
 int check_unsafe_exec(struct linux_binprm *bprm)
@@ -1268,7 +1268,7 @@ int do_execve(char * filename,
        if (!bprm)
                goto out_files;
 
-       retval = mutex_lock_interruptible(&current->cred_exec_mutex);
+       retval = mutex_lock_interruptible(&current->cred_guard_mutex);
        if (retval < 0)
                goto out_free;
        current->in_execve = 1;
@@ -1331,7 +1331,7 @@ int do_execve(char * filename,
        /* execve succeeded */
        current->fs->in_exec = 0;
        current->in_execve = 0;
-       mutex_unlock(&current->cred_exec_mutex);
+       mutex_unlock(&current->cred_guard_mutex);
        acct_update_integrals(current);
        free_bprm(bprm);
        if (displaced)
@@ -1354,7 +1354,7 @@ out_unmark:
 
 out_unlock:
        current->in_execve = 0;
-       mutex_unlock(&current->cred_exec_mutex);
+       mutex_unlock(&current->cred_guard_mutex);
 
 out_free:
        free_bprm(bprm);
index b249ae97fb15bfb24e1835a41d351110c7ae3ef9..06ca92672eb5d6118ee644074019a650a96125f3 100644 (file)
@@ -50,10 +50,10 @@ int exofs_check_ok_resid(struct osd_request *or, u64 *in_resid, u64 *out_resid)
 
        /* FIXME: should be include in osd_sense_info */
        if (in_resid)
-               *in_resid = or->in.req ? or->in.req->data_len : 0;
+               *in_resid = or->in.req ? or->in.req->resid_len : 0;
 
        if (out_resid)
-               *out_resid = or->out.req ? or->out.req->data_len : 0;
+               *out_resid = or->out.req ? or->out.req->resid_len : 0;
 
        return ret;
 }
index 5c4afe652245a9d045825f26f3ad3dbe0a06e13a..e3c748faf2dbcd14ceafb13c6353479e6b072eb9 100644 (file)
@@ -1093,6 +1093,7 @@ failed_mount:
        brelse(bh);
 failed_sbi:
        sb->s_fs_info = NULL;
+       kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
        return ret;
 }
index 599dbfe504c39ef8370dd28a4c65aa05346499b4..3c70d52afb10b0829d9cc262559745c1f985eaa5 100644 (file)
@@ -1696,7 +1696,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                goto failed_mount;
        }
 
-       hblock = bdev_hardsect_size(sb->s_bdev);
+       hblock = bdev_logical_block_size(sb->s_bdev);
        if (sb->s_blocksize != blocksize) {
                /*
                 * Make sure the blocksize for the filesystem is larger
@@ -2021,6 +2021,7 @@ failed_mount:
        brelse(bh);
 out_fail:
        sb->s_fs_info = NULL;
+       kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
        lock_kernel();
        return ret;
@@ -2119,7 +2120,7 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb,
        }
 
        blocksize = sb->s_blocksize;
-       hblock = bdev_hardsect_size(bdev);
+       hblock = bdev_logical_block_size(bdev);
        if (blocksize < hblock) {
                printk(KERN_ERR
                        "EXT3-fs: blocksize too small for journal device.\n");
index a8ff003a00f70b8e09958fcdfa3491c0a4bc5a8f..8a34710ecf40ef1f3577be07f13c9086e5ea888d 100644 (file)
@@ -5,8 +5,8 @@
 obj-$(CONFIG_EXT4_FS) += ext4.o
 
 ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
-                  ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \
-                  ext4_jbd2.o migrate.o mballoc.o
+               ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \
+               ext4_jbd2.o migrate.o mballoc.o block_validity.o
 
 ext4-$(CONFIG_EXT4_FS_XATTR)           += xattr.o xattr_user.o xattr_trusted.o
 ext4-$(CONFIG_EXT4_FS_POSIX_ACL)       += acl.o
index 53c72ad85877314c16c0eef0f19fb3889a6743da..e2126d70dff5bd5fce57506849a91ca1f0a2052e 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/buffer_head.h>
 #include "ext4.h"
 #include "ext4_jbd2.h"
-#include "group.h"
 #include "mballoc.h"
 
 /*
@@ -88,6 +87,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
                 ext4_group_t block_group, struct ext4_group_desc *gdp)
 {
        int bit, bit_max;
+       ext4_group_t ngroups = ext4_get_groups_count(sb);
        unsigned free_blocks, group_blocks;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
@@ -123,7 +123,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
                bit_max += ext4_bg_num_gdb(sb, block_group);
        }
 
-       if (block_group == sbi->s_groups_count - 1) {
+       if (block_group == ngroups - 1) {
                /*
                 * Even though mke2fs always initialize first and last group
                 * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need
@@ -131,7 +131,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
                 */
                group_blocks = ext4_blocks_count(sbi->s_es) -
                        le32_to_cpu(sbi->s_es->s_first_data_block) -
-                       (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count - 1));
+                       (EXT4_BLOCKS_PER_GROUP(sb) * (ngroups - 1));
        } else {
                group_blocks = EXT4_BLOCKS_PER_GROUP(sb);
        }
@@ -205,18 +205,18 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
 {
        unsigned int group_desc;
        unsigned int offset;
+       ext4_group_t ngroups = ext4_get_groups_count(sb);
        struct ext4_group_desc *desc;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
-       if (block_group >= sbi->s_groups_count) {
+       if (block_group >= ngroups) {
                ext4_error(sb, "ext4_get_group_desc",
                           "block_group >= groups_count - "
                           "block_group = %u, groups_count = %u",
-                          block_group, sbi->s_groups_count);
+                          block_group, ngroups);
 
                return NULL;
        }
-       smp_rmb();
 
        group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
        offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
@@ -326,16 +326,16 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
                unlock_buffer(bh);
                return bh;
        }
-       spin_lock(sb_bgl_lock(EXT4_SB(sb), block_group));
+       ext4_lock_group(sb, block_group);
        if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
                ext4_init_block_bitmap(sb, bh, block_group, desc);
                set_bitmap_uptodate(bh);
                set_buffer_uptodate(bh);
-               spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group));
+               ext4_unlock_group(sb, block_group);
                unlock_buffer(bh);
                return bh;
        }
-       spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group));
+       ext4_unlock_group(sb, block_group);
        if (buffer_uptodate(bh)) {
                /*
                 * if not uninit if bh is uptodate,
@@ -451,7 +451,7 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
        down_write(&grp->alloc_sem);
        for (i = 0, blocks_freed = 0; i < count; i++) {
                BUFFER_TRACE(bitmap_bh, "clear bit");
-               if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
+               if (!ext4_clear_bit_atomic(ext4_group_lock_ptr(sb, block_group),
                                                bit + i, bitmap_bh->b_data)) {
                        ext4_error(sb, __func__,
                                   "bit already cleared for block %llu",
@@ -461,11 +461,11 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
                        blocks_freed++;
                }
        }
-       spin_lock(sb_bgl_lock(sbi, block_group));
+       ext4_lock_group(sb, block_group);
        blk_free_count = blocks_freed + ext4_free_blks_count(sb, desc);
        ext4_free_blks_set(sb, desc, blk_free_count);
        desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc);
-       spin_unlock(sb_bgl_lock(sbi, block_group));
+       ext4_unlock_group(sb, block_group);
        percpu_counter_add(&sbi->s_freeblocks_counter, blocks_freed);
 
        if (sbi->s_log_groups_per_flex) {
@@ -665,7 +665,7 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
        ext4_fsblk_t desc_count;
        struct ext4_group_desc *gdp;
        ext4_group_t i;
-       ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
+       ext4_group_t ngroups = ext4_get_groups_count(sb);
 #ifdef EXT4FS_DEBUG
        struct ext4_super_block *es;
        ext4_fsblk_t bitmap_count;
@@ -677,7 +677,6 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
        bitmap_count = 0;
        gdp = NULL;
 
-       smp_rmb();
        for (i = 0; i < ngroups; i++) {
                gdp = ext4_get_group_desc(sb, i, NULL);
                if (!gdp)
@@ -700,7 +699,6 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
        return bitmap_count;
 #else
        desc_count = 0;
-       smp_rmb();
        for (i = 0; i < ngroups; i++) {
                gdp = ext4_get_group_desc(sb, i, NULL);
                if (!gdp)
diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c
new file mode 100644 (file)
index 0000000..50784ef
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ *  linux/fs/ext4/block_validity.c
+ *
+ * Copyright (C) 2009
+ * Theodore Ts'o (tytso@mit.edu)
+ *
+ * Track which blocks in the filesystem are metadata blocks that
+ * should never be used as data blocks by files or directories.
+ */
+
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/quotaops.h>
+#include <linux/buffer_head.h>
+#include <linux/module.h>
+#include <linux/swap.h>
+#include <linux/pagemap.h>
+#include <linux/version.h>
+#include <linux/blkdev.h>
+#include <linux/mutex.h>
+#include "ext4.h"
+
+struct ext4_system_zone {
+       struct rb_node  node;
+       ext4_fsblk_t    start_blk;
+       unsigned int    count;
+};
+
+static struct kmem_cache *ext4_system_zone_cachep;
+
+int __init init_ext4_system_zone(void)
+{
+       ext4_system_zone_cachep = KMEM_CACHE(ext4_system_zone,
+                                            SLAB_RECLAIM_ACCOUNT);
+       if (ext4_system_zone_cachep == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+void exit_ext4_system_zone(void)
+{
+       kmem_cache_destroy(ext4_system_zone_cachep);
+}
+
+static inline int can_merge(struct ext4_system_zone *entry1,
+                    struct ext4_system_zone *entry2)
+{
+       if ((entry1->start_blk + entry1->count) == entry2->start_blk)
+               return 1;
+       return 0;
+}
+
+/*
+ * Mark a range of blocks as belonging to the "system zone" --- that
+ * is, filesystem metadata blocks which should never be used by
+ * inodes.
+ */
+static int add_system_zone(struct ext4_sb_info *sbi,
+                          ext4_fsblk_t start_blk,
+                          unsigned int count)
+{
+       struct ext4_system_zone *new_entry = NULL, *entry;
+       struct rb_node **n = &sbi->system_blks.rb_node, *node;
+       struct rb_node *parent = NULL, *new_node = NULL;
+
+       while (*n) {
+               parent = *n;
+               entry = rb_entry(parent, struct ext4_system_zone, node);
+               if (start_blk < entry->start_blk)
+                       n = &(*n)->rb_left;
+               else if (start_blk >= (entry->start_blk + entry->count))
+                       n = &(*n)->rb_right;
+               else {
+                       if (start_blk + count > (entry->start_blk + 
+                                                entry->count))
+                               entry->count = (start_blk + count - 
+                                               entry->start_blk);
+                       new_node = *n;
+                       new_entry = rb_entry(new_node, struct ext4_system_zone,
+                                            node);
+                       break;
+               }
+       }
+
+       if (!new_entry) {
+               new_entry = kmem_cache_alloc(ext4_system_zone_cachep,
+                                            GFP_KERNEL);
+               if (!new_entry)
+                       return -ENOMEM;
+               new_entry->start_blk = start_blk;
+               new_entry->count = count;
+               new_node = &new_entry->node;
+
+               rb_link_node(new_node, parent, n);
+               rb_insert_color(new_node, &sbi->system_blks);
+       }
+
+       /* Can we merge to the left? */
+       node = rb_prev(new_node);
+       if (node) {
+               entry = rb_entry(node, struct ext4_system_zone, node);
+               if (can_merge(entry, new_entry)) {
+                       new_entry->start_blk = entry->start_blk;
+                       new_entry->count += entry->count;
+                       rb_erase(node, &sbi->system_blks);
+                       kmem_cache_free(ext4_system_zone_cachep, entry);
+               }
+       }
+
+       /* Can we merge to the right? */
+       node = rb_next(new_node);
+       if (node) {
+               entry = rb_entry(node, struct ext4_system_zone, node);
+               if (can_merge(new_entry, entry)) {
+                       new_entry->count += entry->count;
+                       rb_erase(node, &sbi->system_blks);
+                       kmem_cache_free(ext4_system_zone_cachep, entry);
+               }
+       }
+       return 0;
+}
+
+static void debug_print_tree(struct ext4_sb_info *sbi)
+{
+       struct rb_node *node;
+       struct ext4_system_zone *entry;
+       int first = 1;
+
+       printk(KERN_INFO "System zones: ");
+       node = rb_first(&sbi->system_blks);
+       while (node) {
+               entry = rb_entry(node, struct ext4_system_zone, node);
+               printk("%s%llu-%llu", first ? "" : ", ",
+                      entry->start_blk, entry->start_blk + entry->count - 1);
+               first = 0;
+               node = rb_next(node);
+       }
+       printk("\n");
+}
+
+int ext4_setup_system_zone(struct super_block *sb)
+{
+       ext4_group_t ngroups = ext4_get_groups_count(sb);
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       struct ext4_group_desc *gdp;
+       ext4_group_t i;
+       int flex_size = ext4_flex_bg_size(sbi);
+       int ret;
+
+       if (!test_opt(sb, BLOCK_VALIDITY)) {
+               if (EXT4_SB(sb)->system_blks.rb_node)
+                       ext4_release_system_zone(sb);
+               return 0;
+       }
+       if (EXT4_SB(sb)->system_blks.rb_node)
+               return 0;
+
+       for (i=0; i < ngroups; i++) {
+               if (ext4_bg_has_super(sb, i) &&
+                   ((i < 5) || ((i % flex_size) == 0)))
+                       add_system_zone(sbi, ext4_group_first_block_no(sb, i),
+                                       sbi->s_gdb_count + 1);
+               gdp = ext4_get_group_desc(sb, i, NULL);
+               ret = add_system_zone(sbi, ext4_block_bitmap(sb, gdp), 1);
+               if (ret)
+                       return ret;
+               ret = add_system_zone(sbi, ext4_inode_bitmap(sb, gdp), 1);
+               if (ret)
+                       return ret;
+               ret = add_system_zone(sbi, ext4_inode_table(sb, gdp),
+                               sbi->s_itb_per_group);
+               if (ret)
+                       return ret;
+       }
+
+       if (test_opt(sb, DEBUG))
+               debug_print_tree(EXT4_SB(sb));
+       return 0;
+}
+
+/* Called when the filesystem is unmounted */
+void ext4_release_system_zone(struct super_block *sb)
+{
+       struct rb_node  *n = EXT4_SB(sb)->system_blks.rb_node;
+       struct rb_node  *parent;
+       struct ext4_system_zone *entry;
+
+       while (n) {
+               /* Do the node's children first */
+               if (n->rb_left) {
+                       n = n->rb_left;
+                       continue;
+               }
+               if (n->rb_right) {
+                       n = n->rb_right;
+                       continue;
+               }
+               /*
+                * The node has no children; free it, and then zero
+                * out parent's link to it.  Finally go to the
+                * beginning of the loop and try to free the parent
+                * node.
+                */
+               parent = rb_parent(n);
+               entry = rb_entry(n, struct ext4_system_zone, node);
+               kmem_cache_free(ext4_system_zone_cachep, entry);
+               if (!parent)
+                       EXT4_SB(sb)->system_blks.rb_node = NULL;
+               else if (parent->rb_left == n)
+                       parent->rb_left = NULL;
+               else if (parent->rb_right == n)
+                       parent->rb_right = NULL;
+               n = parent;
+       }
+       EXT4_SB(sb)->system_blks.rb_node = NULL;
+}
+
+/*
+ * Returns 1 if the passed-in block region (start_blk,
+ * start_blk+count) is valid; 0 if some part of the block region
+ * overlaps with filesystem metadata blocks.
+ */
+int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk,
+                         unsigned int count)
+{
+       struct ext4_system_zone *entry;
+       struct rb_node *n = sbi->system_blks.rb_node;
+
+       if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
+           (start_blk + count > ext4_blocks_count(sbi->s_es)))
+               return 0;
+       while (n) {
+               entry = rb_entry(n, struct ext4_system_zone, node);
+               if (start_blk + count - 1 < entry->start_blk)
+                       n = n->rb_left;
+               else if (start_blk >= (entry->start_blk + entry->count))
+                       n = n->rb_right;
+               else
+                       return 0;
+       }
+       return 1;
+}
+
index b64789929a65bc00243e9b10298f056aadaeb306..9dc93168e2623ae09d26b1c7287f4fc30975e077 100644 (file)
@@ -131,8 +131,7 @@ static int ext4_readdir(struct file *filp,
                struct buffer_head *bh = NULL;
 
                map_bh.b_state = 0;
-               err = ext4_get_blocks_wrap(NULL, inode, blk, 1, &map_bh,
-                                               0, 0, 0);
+               err = ext4_get_blocks(NULL, inode, blk, 1, &map_bh, 0);
                if (err > 0) {
                        pgoff_t index = map_bh.b_blocknr >>
                                        (PAGE_CACHE_SHIFT - inode->i_blkbits);
index d0f15ef56de1b1b6b325d0a86207e78260b1f40a..cc7d5edc38c904646469094191e4a41f305f8d5b 100644 (file)
 #include <linux/magic.h>
 #include <linux/jbd2.h>
 #include <linux/quota.h>
-#include "ext4_i.h"
+#include <linux/rwsem.h>
+#include <linux/rbtree.h>
+#include <linux/seqlock.h>
+#include <linux/mutex.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/blockgroup_lock.h>
+#include <linux/percpu_counter.h>
 
 /*
  * The fourth extended filesystem constants/structures
 #define ext4_debug(f, a...)    do {} while (0)
 #endif
 
+/* data type for block offset of block group */
+typedef int ext4_grpblk_t;
+
+/* data type for filesystem-wide blocks number */
+typedef unsigned long long ext4_fsblk_t;
+
+/* data type for file logical block number */
+typedef __u32 ext4_lblk_t;
+
+/* data type for block group number */
+typedef unsigned int ext4_group_t;
+
+
 /* prefer goal again. length */
 #define EXT4_MB_HINT_MERGE             1
 /* blocks already reserved */
@@ -179,9 +199,6 @@ struct flex_groups {
 #define EXT4_BG_BLOCK_UNINIT   0x0002 /* Block bitmap not in use */
 #define EXT4_BG_INODE_ZEROED   0x0004 /* On-disk itable initialized to zero */
 
-#ifdef __KERNEL__
-#include "ext4_sb.h"
-#endif
 /*
  * Macro-instructions used to manage group descriptors
  */
@@ -297,10 +314,23 @@ struct ext4_new_group_data {
 };
 
 /*
- * Following is used by preallocation code to tell get_blocks() that we
- * want uninitialzed extents.
+ * Flags used by ext4_get_blocks()
  */
-#define EXT4_CREATE_UNINITIALIZED_EXT          2
+       /* Allocate any needed blocks and/or convert an unitialized
+          extent to be an initialized ext4 */
+#define EXT4_GET_BLOCKS_CREATE                 0x0001
+       /* Request the creation of an unitialized extent */
+#define EXT4_GET_BLOCKS_UNINIT_EXT             0x0002
+#define EXT4_GET_BLOCKS_CREATE_UNINIT_EXT      (EXT4_GET_BLOCKS_UNINIT_EXT|\
+                                                EXT4_GET_BLOCKS_CREATE)
+       /* Caller is from the delayed allocation writeout path,
+          so set the magic i_delalloc_reserve_flag after taking the 
+          inode allocation semaphore for */
+#define EXT4_GET_BLOCKS_DELALLOC_RESERVE       0x0004
+       /* Call ext4_da_update_reserve_space() after successfully 
+          allocating the blocks */
+#define EXT4_GET_BLOCKS_UPDATE_RESERVE_SPACE   0x0008
+
 
 /*
  * ioctl commands
@@ -515,6 +545,110 @@ do {                                                                             \
 
 #endif /* defined(__KERNEL__) || defined(__linux__) */
 
+/*
+ * storage for cached extent
+ */
+struct ext4_ext_cache {
+       ext4_fsblk_t    ec_start;
+       ext4_lblk_t     ec_block;
+       __u32           ec_len; /* must be 32bit to return holes */
+       __u32           ec_type;
+};
+
+/*
+ * fourth extended file system inode data in memory
+ */
+struct ext4_inode_info {
+       __le32  i_data[15];     /* unconverted */
+       __u32   i_flags;
+       ext4_fsblk_t    i_file_acl;
+       __u32   i_dtime;
+
+       /*
+        * i_block_group is the number of the block group which contains
+        * this file's inode.  Constant across the lifetime of the inode,
+        * it is ued for making block allocation decisions - we try to
+        * place a file's data blocks near its inode block, and new inodes
+        * near to their parent directory's inode.
+        */
+       ext4_group_t    i_block_group;
+       __u32   i_state;                /* Dynamic state flags for ext4 */
+
+       ext4_lblk_t             i_dir_start_lookup;
+#ifdef CONFIG_EXT4_FS_XATTR
+       /*
+        * Extended attributes can be read independently of the main file
+        * data. Taking i_mutex even when reading would cause contention
+        * between readers of EAs and writers of regular file data, so
+        * instead we synchronize on xattr_sem when reading or changing
+        * EAs.
+        */
+       struct rw_semaphore xattr_sem;
+#endif
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
+       struct posix_acl        *i_acl;
+       struct posix_acl        *i_default_acl;
+#endif
+
+       struct list_head i_orphan;      /* unlinked but open inodes */
+
+       /*
+        * i_disksize keeps track of what the inode size is ON DISK, not
+        * in memory.  During truncate, i_size is set to the new size by
+        * the VFS prior to calling ext4_truncate(), but the filesystem won't
+        * set i_disksize to 0 until the truncate is actually under way.
+        *
+        * The intent is that i_disksize always represents the blocks which
+        * are used by this file.  This allows recovery to restart truncate
+        * on orphans if we crash during truncate.  We actually write i_disksize
+        * into the on-disk inode when writing inodes out, instead of i_size.
+        *
+        * The only time when i_disksize and i_size may be different is when
+        * a truncate is in progress.  The only things which change i_disksize
+        * are ext4_get_block (growth) and ext4_truncate (shrinkth).
+        */
+       loff_t  i_disksize;
+
+       /*
+        * i_data_sem is for serialising ext4_truncate() against
+        * ext4_getblock().  In the 2.4 ext2 design, great chunks of inode's
+        * data tree are chopped off during truncate. We can't do that in
+        * ext4 because whenever we perform intermediate commits during
+        * truncate, the inode and all the metadata blocks *must* be in a
+        * consistent state which allows truncation of the orphans to restart
+        * during recovery.  Hence we must fix the get_block-vs-truncate race
+        * by other means, so we have i_data_sem.
+        */
+       struct rw_semaphore i_data_sem;
+       struct inode vfs_inode;
+       struct jbd2_inode jinode;
+
+       struct ext4_ext_cache i_cached_extent;
+       /*
+        * File creation time. Its function is same as that of
+        * struct timespec i_{a,c,m}time in the generic inode.
+        */
+       struct timespec i_crtime;
+
+       /* mballoc */
+       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;
+       unsigned int i_allocated_meta_blocks;
+       unsigned short i_delalloc_reserved_flag;
+
+       /* on-disk additional length */
+       __u16 i_extra_isize;
+
+       spinlock_t i_block_reservation_lock;
+};
+
 /*
  * File system states
  */
@@ -560,6 +694,7 @@ do {                                                                               \
 #define EXT4_MOUNT_I_VERSION            0x2000000 /* i_version support */
 #define EXT4_MOUNT_DELALLOC            0x8000000 /* Delalloc support */
 #define EXT4_MOUNT_DATA_ERR_ABORT      0x10000000 /* Abort on file data write */
+#define EXT4_MOUNT_BLOCK_VALIDITY      0x20000000 /* Block validity checking */
 
 /* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */
 #ifndef _LINUX_EXT2_FS_H
@@ -689,6 +824,137 @@ struct ext4_super_block {
 };
 
 #ifdef __KERNEL__
+/*
+ * fourth extended-fs super-block data in memory
+ */
+struct ext4_sb_info {
+       unsigned long s_desc_size;      /* Size of a group descriptor in bytes */
+       unsigned long s_inodes_per_block;/* Number of inodes per block */
+       unsigned long s_blocks_per_group;/* Number of blocks in a group */
+       unsigned long s_inodes_per_group;/* Number of inodes in a group */
+       unsigned long s_itb_per_group;  /* Number of inode table blocks per group */
+       unsigned long s_gdb_count;      /* Number of group descriptor blocks */
+       unsigned long s_desc_per_block; /* Number of group descriptors per block */
+       ext4_group_t s_groups_count;    /* Number of groups in the fs */
+       unsigned long s_overhead_last;  /* Last calculated overhead */
+       unsigned long s_blocks_last;    /* Last seen block count */
+       loff_t s_bitmap_maxbytes;       /* max bytes for bitmap files */
+       struct buffer_head * s_sbh;     /* Buffer containing the super block */
+       struct ext4_super_block *s_es;  /* Pointer to the super block in the buffer */
+       struct buffer_head **s_group_desc;
+       unsigned long  s_mount_opt;
+       ext4_fsblk_t s_sb_block;
+       uid_t s_resuid;
+       gid_t s_resgid;
+       unsigned short s_mount_state;
+       unsigned short s_pad;
+       int s_addr_per_block_bits;
+       int s_desc_per_block_bits;
+       int s_inode_size;
+       int s_first_ino;
+       unsigned int s_inode_readahead_blks;
+       spinlock_t s_next_gen_lock;
+       u32 s_next_generation;
+       u32 s_hash_seed[4];
+       int s_def_hash_version;
+       int s_hash_unsigned;    /* 3 if hash should be signed, 0 if not */
+       struct percpu_counter s_freeblocks_counter;
+       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 proc_dir_entry *s_proc;
+       struct kobject s_kobj;
+       struct completion s_kobj_unregister;
+
+       /* Journaling */
+       struct inode *s_journal_inode;
+       struct journal_s *s_journal;
+       struct list_head s_orphan;
+       struct mutex s_orphan_lock;
+       struct mutex s_resize_lock;
+       unsigned long s_commit_interval;
+       u32 s_max_batch_time;
+       u32 s_min_batch_time;
+       struct block_device *journal_bdev;
+#ifdef CONFIG_JBD2_DEBUG
+       struct timer_list turn_ro_timer;        /* For turning read-only (crash simulation) */
+       wait_queue_head_t ro_wait_queue;        /* For people waiting for the fs to go read-only */
+#endif
+#ifdef CONFIG_QUOTA
+       char *s_qf_names[MAXQUOTAS];            /* Names of quota files with journalled quota */
+       int s_jquota_fmt;                       /* Format of quota to use */
+#endif
+       unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */
+       struct rb_root system_blks;
+
+#ifdef EXTENTS_STATS
+       /* ext4 extents stats */
+       unsigned long s_ext_min;
+       unsigned long s_ext_max;
+       unsigned long s_depth_max;
+       spinlock_t s_ext_stats_lock;
+       unsigned long s_ext_blocks;
+       unsigned long s_ext_extents;
+#endif
+
+       /* for buddy allocator */
+       struct ext4_group_info ***s_group_info;
+       struct inode *s_buddy_cache;
+       long s_blocks_reserved;
+       spinlock_t s_reserve_lock;
+       spinlock_t s_md_lock;
+       tid_t s_last_transaction;
+       unsigned short *s_mb_offsets;
+       unsigned int *s_mb_maxs;
+
+       /* tunables */
+       unsigned long s_stripe;
+       unsigned int s_mb_stream_request;
+       unsigned int s_mb_max_to_scan;
+       unsigned int s_mb_min_to_scan;
+       unsigned int s_mb_stats;
+       unsigned int s_mb_order2_reqs;
+       unsigned int s_mb_group_prealloc;
+       /* where last allocation was done - for stream allocation */
+       unsigned long s_mb_last_group;
+       unsigned long s_mb_last_start;
+
+       /* history to debug policy */
+       struct ext4_mb_history *s_mb_history;
+       int s_mb_history_cur;
+       int s_mb_history_max;
+       int s_mb_history_num;
+       spinlock_t s_mb_history_lock;
+       int s_mb_history_filter;
+
+       /* stats for buddy allocator */
+       spinlock_t s_mb_pa_lock;
+       atomic_t s_bal_reqs;    /* number of reqs with len > 1 */
+       atomic_t s_bal_success; /* we found long enough chunks */
+       atomic_t s_bal_allocated;       /* in blocks */
+       atomic_t s_bal_ex_scanned;      /* total extents scanned */
+       atomic_t s_bal_goals;   /* goal hits */
+       atomic_t s_bal_breaks;  /* too long searches */
+       atomic_t s_bal_2orders; /* 2^order hits */
+       spinlock_t s_bal_lock;
+       unsigned long s_mb_buddies_generated;
+       unsigned long long s_mb_generation_time;
+       atomic_t s_mb_lost_chunks;
+       atomic_t s_mb_preallocated;
+       atomic_t s_mb_discarded;
+
+       /* 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;
+};
+
 static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
 {
        return sb->s_fs_info;
@@ -704,7 +970,6 @@ static inline struct timespec ext4_current_time(struct inode *inode)
                current_fs_time(inode->i_sb) : CURRENT_TIME_SEC;
 }
 
-
 static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 {
        return ino == EXT4_ROOT_INO ||
@@ -1014,6 +1279,14 @@ extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
                                                    ext4_group_t block_group,
                                                    struct buffer_head ** bh);
 extern int ext4_should_retry_alloc(struct super_block *sb, int *retries);
+struct buffer_head *ext4_read_block_bitmap(struct super_block *sb,
+                                     ext4_group_t block_group);
+extern unsigned ext4_init_block_bitmap(struct super_block *sb,
+                                      struct buffer_head *bh,
+                                      ext4_group_t group,
+                                      struct ext4_group_desc *desc);
+#define ext4_free_blocks_after_init(sb, group, desc)                   \
+               ext4_init_block_bitmap(sb, NULL, group, desc)
 
 /* dir.c */
 extern int ext4_check_dir_entry(const char *, struct inode *,
@@ -1038,6 +1311,11 @@ extern struct inode * ext4_orphan_get(struct super_block *, unsigned long);
 extern unsigned long ext4_count_free_inodes(struct super_block *);
 extern unsigned long ext4_count_dirs(struct super_block *);
 extern void ext4_check_inodes_bitmap(struct super_block *);
+extern unsigned ext4_init_inode_bitmap(struct super_block *sb,
+                                      struct buffer_head *bh,
+                                      ext4_group_t group,
+                                      struct ext4_group_desc *desc);
+extern void mark_bitmap_end(int start_bit, int end_bit, char *bitmap);
 
 /* mballoc.c */
 extern long ext4_mb_stats;
@@ -1123,6 +1401,8 @@ extern void ext4_abort(struct super_block *, const char *, const char *, ...)
        __attribute__ ((format (printf, 3, 4)));
 extern void ext4_warning(struct super_block *, const char *, const char *, ...)
        __attribute__ ((format (printf, 3, 4)));
+extern void ext4_msg(struct super_block *, const char *, const char *, ...)
+       __attribute__ ((format (printf, 3, 4)));
 extern void ext4_grp_locked_error(struct super_block *, ext4_group_t,
                                const char *, const char *, ...)
        __attribute__ ((format (printf, 4, 5)));
@@ -1161,6 +1441,10 @@ extern void ext4_used_dirs_set(struct super_block *sb,
                                struct ext4_group_desc *bg, __u32 count);
 extern void ext4_itable_unused_set(struct super_block *sb,
                                   struct ext4_group_desc *bg, __u32 count);
+extern __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 group,
+                                  struct ext4_group_desc *gdp);
+extern int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 group,
+                                      struct ext4_group_desc *gdp);
 
 static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
 {
@@ -1228,6 +1512,18 @@ struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
         return grp_info[indexv][indexh];
 }
 
+/*
+ * Reading s_groups_count requires using smp_rmb() afterwards.  See
+ * the locking protocol documented in the comments of ext4_group_add()
+ * in resize.c
+ */
+static inline ext4_group_t ext4_get_groups_count(struct super_block *sb)
+{
+       ext4_group_t    ngroups = EXT4_SB(sb)->s_groups_count;
+
+       smp_rmb();
+       return ngroups;
+}
 
 static inline ext4_group_t ext4_flex_group(struct ext4_sb_info *sbi,
                                             ext4_group_t block_group)
@@ -1283,33 +1579,25 @@ struct ext4_group_info {
 };
 
 #define EXT4_GROUP_INFO_NEED_INIT_BIT  0
-#define EXT4_GROUP_INFO_LOCKED_BIT     1
 
 #define EXT4_MB_GRP_NEED_INIT(grp)     \
        (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
 
-static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group)
+static inline spinlock_t *ext4_group_lock_ptr(struct super_block *sb,
+                                             ext4_group_t group)
 {
-       struct ext4_group_info *grinfo = ext4_get_group_info(sb, group);
-
-       bit_spin_lock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state));
+       return bgl_lock_ptr(EXT4_SB(sb)->s_blockgroup_lock, group);
 }
 
-static inline void ext4_unlock_group(struct super_block *sb,
-                                       ext4_group_t group)
+static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group)
 {
-       struct ext4_group_info *grinfo = ext4_get_group_info(sb, group);
-
-       bit_spin_unlock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state));
+       spin_lock(ext4_group_lock_ptr(sb, group));
 }
 
-static inline int ext4_is_group_locked(struct super_block *sb,
+static inline void ext4_unlock_group(struct super_block *sb,
                                        ext4_group_t group)
 {
-       struct ext4_group_info *grinfo = ext4_get_group_info(sb, group);
-
-       return bit_spin_is_locked(EXT4_GROUP_INFO_LOCKED_BIT,
-                                               &(grinfo->bb_state));
+       spin_unlock(ext4_group_lock_ptr(sb, group));
 }
 
 /*
@@ -1326,11 +1614,21 @@ extern const struct file_operations ext4_file_operations;
 /* namei.c */
 extern const struct inode_operations ext4_dir_inode_operations;
 extern const struct inode_operations ext4_special_inode_operations;
+extern struct dentry *ext4_get_parent(struct dentry *child);
 
 /* symlink.c */
 extern const struct inode_operations ext4_symlink_inode_operations;
 extern const struct inode_operations ext4_fast_symlink_inode_operations;
 
+/* block_validity */
+extern void ext4_release_system_zone(struct super_block *sb);
+extern int ext4_setup_system_zone(struct super_block *sb);
+extern int __init init_ext4_system_zone(void);
+extern void exit_ext4_system_zone(void);
+extern int ext4_data_block_valid(struct ext4_sb_info *sbi,
+                                ext4_fsblk_t start_blk,
+                                unsigned int count);
+
 /* extents.c */
 extern int ext4_ext_tree_init(handle_t *handle, struct inode *);
 extern int ext4_ext_writepage_trans_blocks(struct inode *, int);
@@ -1338,17 +1636,15 @@ extern int ext4_ext_index_trans_blocks(struct inode *inode, int nrblocks,
                                       int chunk);
 extern int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                               ext4_lblk_t iblock, unsigned int max_blocks,
-                              struct buffer_head *bh_result,
-                              int create, int extend_disksize);
+                              struct buffer_head *bh_result, int flags);
 extern void ext4_ext_truncate(struct inode *);
 extern void ext4_ext_init(struct super_block *);
 extern void ext4_ext_release(struct super_block *);
 extern long ext4_fallocate(struct inode *inode, int mode, loff_t offset,
                          loff_t len);
-extern int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode,
-                       sector_t block, unsigned int max_blocks,
-                       struct buffer_head *bh, int create,
-                       int extend_disksize, int flag);
+extern int ext4_get_blocks(handle_t *handle, struct inode *inode,
+                          sector_t block, unsigned int max_blocks,
+                          struct buffer_head *bh, int flags);
 extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                        __u64 start, __u64 len);
 
diff --git a/fs/ext4/ext4_i.h b/fs/ext4/ext4_i.h
deleted file mode 100644 (file)
index 4ce2187..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- *  ext4_i.h
- *
- * 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/include/linux/minix_fs_i.h
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-#ifndef _EXT4_I
-#define _EXT4_I
-
-#include <linux/rwsem.h>
-#include <linux/rbtree.h>
-#include <linux/seqlock.h>
-#include <linux/mutex.h>
-
-/* data type for block offset of block group */
-typedef int ext4_grpblk_t;
-
-/* data type for filesystem-wide blocks number */
-typedef unsigned long long ext4_fsblk_t;
-
-/* data type for file logical block number */
-typedef __u32 ext4_lblk_t;
-
-/* data type for block group number */
-typedef unsigned int ext4_group_t;
-
-/*
- * storage for cached extent
- */
-struct ext4_ext_cache {
-       ext4_fsblk_t    ec_start;
-       ext4_lblk_t     ec_block;
-       __u32           ec_len; /* must be 32bit to return holes */
-       __u32           ec_type;
-};
-
-/*
- * fourth extended file system inode data in memory
- */
-struct ext4_inode_info {
-       __le32  i_data[15];     /* unconverted */
-       __u32   i_flags;
-       ext4_fsblk_t    i_file_acl;
-       __u32   i_dtime;
-
-       /*
-        * i_block_group is the number of the block group which contains
-        * this file's inode.  Constant across the lifetime of the inode,
-        * it is ued for making block allocation decisions - we try to
-        * place a file's data blocks near its inode block, and new inodes
-        * near to their parent directory's inode.
-        */
-       ext4_group_t    i_block_group;
-       __u32   i_state;                /* Dynamic state flags for ext4 */
-
-       ext4_lblk_t             i_dir_start_lookup;
-#ifdef CONFIG_EXT4_FS_XATTR
-       /*
-        * Extended attributes can be read independently of the main file
-        * data. Taking i_mutex even when reading would cause contention
-        * between readers of EAs and writers of regular file data, so
-        * instead we synchronize on xattr_sem when reading or changing
-        * EAs.
-        */
-       struct rw_semaphore xattr_sem;
-#endif
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
-       struct posix_acl        *i_acl;
-       struct posix_acl        *i_default_acl;
-#endif
-
-       struct list_head i_orphan;      /* unlinked but open inodes */
-
-       /*
-        * i_disksize keeps track of what the inode size is ON DISK, not
-        * in memory.  During truncate, i_size is set to the new size by
-        * the VFS prior to calling ext4_truncate(), but the filesystem won't
-        * set i_disksize to 0 until the truncate is actually under way.
-        *
-        * The intent is that i_disksize always represents the blocks which
-        * are used by this file.  This allows recovery to restart truncate
-        * on orphans if we crash during truncate.  We actually write i_disksize
-        * into the on-disk inode when writing inodes out, instead of i_size.
-        *
-        * The only time when i_disksize and i_size may be different is when
-        * a truncate is in progress.  The only things which change i_disksize
-        * are ext4_get_block (growth) and ext4_truncate (shrinkth).
-        */
-       loff_t  i_disksize;
-
-       /*
-        * i_data_sem is for serialising ext4_truncate() against
-        * ext4_getblock().  In the 2.4 ext2 design, great chunks of inode's
-        * data tree are chopped off during truncate. We can't do that in
-        * ext4 because whenever we perform intermediate commits during
-        * truncate, the inode and all the metadata blocks *must* be in a
-        * consistent state which allows truncation of the orphans to restart
-        * during recovery.  Hence we must fix the get_block-vs-truncate race
-        * by other means, so we have i_data_sem.
-        */
-       struct rw_semaphore i_data_sem;
-       struct inode vfs_inode;
-       struct jbd2_inode jinode;
-
-       struct ext4_ext_cache i_cached_extent;
-       /*
-        * File creation time. Its function is same as that of
-        * struct timespec i_{a,c,m}time in the generic inode.
-        */
-       struct timespec i_crtime;
-
-       /* mballoc */
-       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;
-       unsigned int i_allocated_meta_blocks;
-       unsigned short i_delalloc_reserved_flag;
-
-       /* on-disk additional length */
-       __u16 i_extra_isize;
-
-       spinlock_t i_block_reservation_lock;
-};
-
-#endif /* _EXT4_I */
diff --git a/fs/ext4/ext4_sb.h b/fs/ext4/ext4_sb.h
deleted file mode 100644 (file)
index 57b71fe..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- *  ext4_sb.h
- *
- * 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/include/linux/minix_fs_sb.h
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-#ifndef _EXT4_SB
-#define _EXT4_SB
-
-#ifdef __KERNEL__
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/blockgroup_lock.h>
-#include <linux/percpu_counter.h>
-#endif
-#include <linux/rbtree.h>
-
-/*
- * fourth extended-fs super-block data in memory
- */
-struct ext4_sb_info {
-       unsigned long s_desc_size;      /* Size of a group descriptor in bytes */
-       unsigned long s_inodes_per_block;/* Number of inodes per block */
-       unsigned long s_blocks_per_group;/* Number of blocks in a group */
-       unsigned long s_inodes_per_group;/* Number of inodes in a group */
-       unsigned long s_itb_per_group;  /* Number of inode table blocks per group */
-       unsigned long s_gdb_count;      /* Number of group descriptor blocks */
-       unsigned long s_desc_per_block; /* Number of group descriptors per block */
-       ext4_group_t s_groups_count;    /* Number of groups in the fs */
-       unsigned long s_overhead_last;  /* Last calculated overhead */
-       unsigned long s_blocks_last;    /* Last seen block count */
-       loff_t s_bitmap_maxbytes;       /* max bytes for bitmap files */
-       struct buffer_head * s_sbh;     /* Buffer containing the super block */
-       struct ext4_super_block *s_es;  /* Pointer to the super block in the buffer */
-       struct buffer_head **s_group_desc;
-       unsigned long  s_mount_opt;
-       ext4_fsblk_t s_sb_block;
-       uid_t s_resuid;
-       gid_t s_resgid;
-       unsigned short s_mount_state;
-       unsigned short s_pad;
-       int s_addr_per_block_bits;
-       int s_desc_per_block_bits;
-       int s_inode_size;
-       int s_first_ino;
-       unsigned int s_inode_readahead_blks;
-       spinlock_t s_next_gen_lock;
-       u32 s_next_generation;
-       u32 s_hash_seed[4];
-       int s_def_hash_version;
-       int s_hash_unsigned;    /* 3 if hash should be signed, 0 if not */
-       struct percpu_counter s_freeblocks_counter;
-       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 proc_dir_entry *s_proc;
-       struct kobject s_kobj;
-       struct completion s_kobj_unregister;
-
-       /* Journaling */
-       struct inode *s_journal_inode;
-       struct journal_s *s_journal;
-       struct list_head s_orphan;
-       unsigned long s_commit_interval;
-       u32 s_max_batch_time;
-       u32 s_min_batch_time;
-       struct block_device *journal_bdev;
-#ifdef CONFIG_JBD2_DEBUG
-       struct timer_list turn_ro_timer;        /* For turning read-only (crash simulation) */
-       wait_queue_head_t ro_wait_queue;        /* For people waiting for the fs to go read-only */
-#endif
-#ifdef CONFIG_QUOTA
-       char *s_qf_names[MAXQUOTAS];            /* Names of quota files with journalled quota */
-       int s_jquota_fmt;                       /* Format of quota to use */
-#endif
-       unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */
-
-#ifdef EXTENTS_STATS
-       /* ext4 extents stats */
-       unsigned long s_ext_min;
-       unsigned long s_ext_max;
-       unsigned long s_depth_max;
-       spinlock_t s_ext_stats_lock;
-       unsigned long s_ext_blocks;
-       unsigned long s_ext_extents;
-#endif
-
-       /* for buddy allocator */
-       struct ext4_group_info ***s_group_info;
-       struct inode *s_buddy_cache;
-       long s_blocks_reserved;
-       spinlock_t s_reserve_lock;
-       spinlock_t s_md_lock;
-       tid_t s_last_transaction;
-       unsigned short *s_mb_offsets;
-       unsigned int *s_mb_maxs;
-
-       /* tunables */
-       unsigned long s_stripe;
-       unsigned int s_mb_stream_request;
-       unsigned int s_mb_max_to_scan;
-       unsigned int s_mb_min_to_scan;
-       unsigned int s_mb_stats;
-       unsigned int s_mb_order2_reqs;
-       unsigned int s_mb_group_prealloc;
-       /* where last allocation was done - for stream allocation */
-       unsigned long s_mb_last_group;
-       unsigned long s_mb_last_start;
-
-       /* history to debug policy */
-       struct ext4_mb_history *s_mb_history;
-       int s_mb_history_cur;
-       int s_mb_history_max;
-       int s_mb_history_num;
-       spinlock_t s_mb_history_lock;
-       int s_mb_history_filter;
-
-       /* stats for buddy allocator */
-       spinlock_t s_mb_pa_lock;
-       atomic_t s_bal_reqs;    /* number of reqs with len > 1 */
-       atomic_t s_bal_success; /* we found long enough chunks */
-       atomic_t s_bal_allocated;       /* in blocks */
-       atomic_t s_bal_ex_scanned;      /* total extents scanned */
-       atomic_t s_bal_goals;   /* goal hits */
-       atomic_t s_bal_breaks;  /* too long searches */
-       atomic_t s_bal_2orders; /* 2^order hits */
-       spinlock_t s_bal_lock;
-       unsigned long s_mb_buddies_generated;
-       unsigned long long s_mb_generation_time;
-       atomic_t s_mb_lost_chunks;
-       atomic_t s_mb_preallocated;
-       atomic_t s_mb_discarded;
-
-       /* 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;
-};
-
-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);
-}
-
-#endif /* _EXT4_SB */
index e3a55eb8b26a5df9cc41fb5efd79e23fc275da22..2593f748c3a48040ef3e70c6a8032d58b8c714e5 100644 (file)
@@ -326,32 +326,18 @@ ext4_ext_max_entries(struct inode *inode, int depth)
 
 static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext)
 {
-       ext4_fsblk_t block = ext_pblock(ext), valid_block;
+       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;
 
-       valid_block = le32_to_cpu(es->s_first_data_block) +
-               EXT4_SB(inode->i_sb)->s_gdb_count;
-       if (unlikely(block <= valid_block ||
-                    ((block + len) > ext4_blocks_count(es))))
-               return 0;
-       else
-               return 1;
+       return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len);
 }
 
 static int ext4_valid_extent_idx(struct inode *inode,
                                struct ext4_extent_idx *ext_idx)
 {
-       ext4_fsblk_t block = idx_pblock(ext_idx), valid_block;
-       struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
+       ext4_fsblk_t block = idx_pblock(ext_idx);
 
-       valid_block = le32_to_cpu(es->s_first_data_block) +
-               EXT4_SB(inode->i_sb)->s_gdb_count;
-       if (unlikely(block <= valid_block ||
-                    (block >= ext4_blocks_count(es))))
-               return 0;
-       else
-               return 1;
+       return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, 1);
 }
 
 static int ext4_valid_extent_entries(struct inode *inode,
@@ -2097,12 +2083,16 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
        ex = EXT_LAST_EXTENT(eh);
 
        ex_ee_block = le32_to_cpu(ex->ee_block);
-       if (ext4_ext_is_uninitialized(ex))
-               uninitialized = 1;
        ex_ee_len = ext4_ext_get_actual_len(ex);
 
        while (ex >= EXT_FIRST_EXTENT(eh) &&
                        ex_ee_block + ex_ee_len > start) {
+
+               if (ext4_ext_is_uninitialized(ex))
+                       uninitialized = 1;
+               else
+                       uninitialized = 0;
+
                ext_debug("remove ext %lu:%u\n", ex_ee_block, ex_ee_len);
                path[depth].p_ext = ex;
 
@@ -2784,7 +2774,7 @@ fix_extent_len:
 int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                        ext4_lblk_t iblock,
                        unsigned int max_blocks, struct buffer_head *bh_result,
-                       int create, int extend_disksize)
+                       int flags)
 {
        struct ext4_ext_path *path = NULL;
        struct ext4_extent_header *eh;
@@ -2793,7 +2783,6 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        int err = 0, depth, ret, cache_type;
        unsigned int allocated = 0;
        struct ext4_allocation_request ar;
-       loff_t disksize;
 
        __clear_bit(BH_New, &bh_result->b_state);
        ext_debug("blocks %u/%u requested for inode %u\n",
@@ -2803,7 +2792,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        cache_type = ext4_ext_in_cache(inode, iblock, &newex);
        if (cache_type) {
                if (cache_type == EXT4_EXT_CACHE_GAP) {
-                       if (!create) {
+                       if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
                                /*
                                 * block isn't allocated yet and
                                 * user doesn't want to allocate it
@@ -2869,9 +2858,11 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                                                        EXT4_EXT_CACHE_EXTENT);
                                goto out;
                        }
-                       if (create == EXT4_CREATE_UNINITIALIZED_EXT)
+                       if (flags & EXT4_GET_BLOCKS_UNINIT_EXT)
                                goto out;
-                       if (!create) {
+                       if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
+                               if (allocated > max_blocks)
+                                       allocated = max_blocks;
                                /*
                                 * We have blocks reserved already.  We
                                 * return allocated blocks so that delalloc
@@ -2879,8 +2870,6 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                                 * the buffer head will be unmapped so that
                                 * a read from the block returns 0s.
                                 */
-                               if (allocated > max_blocks)
-                                       allocated = max_blocks;
                                set_buffer_unwritten(bh_result);
                                bh_result->b_bdev = inode->i_sb->s_bdev;
                                bh_result->b_blocknr = newblock;
@@ -2903,7 +2892,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
         * requested block isn't allocated yet;
         * we couldn't try to create block if create flag is zero
         */
-       if (!create) {
+       if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
                /*
                 * put just found gap into cache to speed up
                 * subsequent requests
@@ -2932,10 +2921,10 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
         * EXT_UNINIT_MAX_LEN.
         */
        if (max_blocks > EXT_INIT_MAX_LEN &&
-           create != EXT4_CREATE_UNINITIALIZED_EXT)
+           !(flags & EXT4_GET_BLOCKS_UNINIT_EXT))
                max_blocks = EXT_INIT_MAX_LEN;
        else if (max_blocks > EXT_UNINIT_MAX_LEN &&
-                create == EXT4_CREATE_UNINITIALIZED_EXT)
+                (flags & EXT4_GET_BLOCKS_UNINIT_EXT))
                max_blocks = EXT_UNINIT_MAX_LEN;
 
        /* Check if we can really insert (iblock)::(iblock+max_blocks) extent */
@@ -2966,7 +2955,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        /* try to insert new extent into found leaf and return */
        ext4_ext_store_pblock(&newex, newblock);
        newex.ee_len = cpu_to_le16(ar.len);
-       if (create == EXT4_CREATE_UNINITIALIZED_EXT)  /* Mark uninitialized */
+       if (flags & EXT4_GET_BLOCKS_UNINIT_EXT)  /* Mark uninitialized */
                ext4_ext_mark_uninitialized(&newex);
        err = ext4_ext_insert_extent(handle, inode, path, &newex);
        if (err) {
@@ -2983,18 +2972,10 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        newblock = ext_pblock(&newex);
        allocated = ext4_ext_get_actual_len(&newex);
 outnew:
-       if (extend_disksize) {
-               disksize = ((loff_t) iblock + ar.len) << inode->i_blkbits;
-               if (disksize > i_size_read(inode))
-                       disksize = i_size_read(inode);
-               if (disksize > EXT4_I(inode)->i_disksize)
-                       EXT4_I(inode)->i_disksize = disksize;
-       }
-
        set_buffer_new(bh_result);
 
        /* Cache only when it is _not_ an uninitialized extent */
-       if (create != EXT4_CREATE_UNINITIALIZED_EXT)
+       if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0)
                ext4_ext_put_in_cache(inode, iblock, allocated, newblock,
                                                EXT4_EXT_CACHE_EXTENT);
 out:
@@ -3150,9 +3131,10 @@ retry:
                        ret = PTR_ERR(handle);
                        break;
                }
-               ret = ext4_get_blocks_wrap(handle, inode, block,
-                                         max_blocks, &map_bh,
-                                         EXT4_CREATE_UNINITIALIZED_EXT, 0, 0);
+               map_bh.b_state = 0;
+               ret = ext4_get_blocks(handle, inode, block,
+                                     max_blocks, &map_bh,
+                                     EXT4_GET_BLOCKS_CREATE_UNINIT_EXT);
                if (ret <= 0) {
 #ifdef EXT4FS_DEBUG
                        WARN_ON(ret <= 0);
@@ -3195,7 +3177,7 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
                       void *data)
 {
        struct fiemap_extent_info *fieinfo = data;
-       unsigned long blksize_bits = inode->i_sb->s_blocksize_bits;
+       unsigned char blksize_bits = inode->i_sb->s_blocksize_bits;
        __u64   logical;
        __u64   physical;
        __u64   length;
@@ -3242,9 +3224,16 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
         *
         * XXX this might miss a single-block extent at EXT_MAX_BLOCK
         */
-       if (logical + length - 1 == EXT_MAX_BLOCK ||
-           ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK)
+       if (ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK ||
+           newex->ec_block + newex->ec_len - 1 == EXT_MAX_BLOCK) {
+               loff_t size = i_size_read(inode);
+               loff_t bs = EXT4_BLOCK_SIZE(inode->i_sb);
+
                flags |= FIEMAP_EXTENT_LAST;
+               if ((flags & FIEMAP_EXTENT_DELALLOC) &&
+                   logical+length > size)
+                       length = (size - logical + bs - 1) & ~(bs-1);
+       }
 
        error = fiemap_fill_next_extent(fieinfo, logical, physical,
                                        length, flags);
@@ -3318,10 +3307,10 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                 * Walk the extent tree gathering extent information.
                 * ext4_ext_fiemap_cb will push extents back to user.
                 */
-               down_write(&EXT4_I(inode)->i_data_sem);
+               down_read(&EXT4_I(inode)->i_data_sem);
                error = ext4_ext_walk_space(inode, start_blk, len_blks,
                                          ext4_ext_fiemap_cb, fieinfo);
-               up_write(&EXT4_I(inode)->i_data_sem);
+               up_read(&EXT4_I(inode)->i_data_sem);
        }
 
        return error;
diff --git a/fs/ext4/group.h b/fs/ext4/group.h
deleted file mode 100644 (file)
index c2c0a8d..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- *  linux/fs/ext4/group.h
- *
- * Copyright (C) 2007 Cluster File Systems, Inc
- *
- * Author: Andreas Dilger <adilger@clusterfs.com>
- */
-
-#ifndef _LINUX_EXT4_GROUP_H
-#define _LINUX_EXT4_GROUP_H
-
-extern __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 group,
-                                  struct ext4_group_desc *gdp);
-extern int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 group,
-                                      struct ext4_group_desc *gdp);
-struct buffer_head *ext4_read_block_bitmap(struct super_block *sb,
-                                     ext4_group_t block_group);
-extern unsigned ext4_init_block_bitmap(struct super_block *sb,
-                                      struct buffer_head *bh,
-                                      ext4_group_t group,
-                                      struct ext4_group_desc *desc);
-#define ext4_free_blocks_after_init(sb, group, desc)                   \
-               ext4_init_block_bitmap(sb, NULL, group, desc)
-extern unsigned ext4_init_inode_bitmap(struct super_block *sb,
-                                      struct buffer_head *bh,
-                                      ext4_group_t group,
-                                      struct ext4_group_desc *desc);
-extern void mark_bitmap_end(int start_bit, int end_bit, char *bitmap);
-#endif /* _LINUX_EXT4_GROUP_H */
index f18e0a08a6b5080cf4b788a06c98abc59c8aca34..3743bd849bce83d4085940acdec32bee72bbd999 100644 (file)
@@ -27,7 +27,6 @@
 #include "ext4_jbd2.h"
 #include "xattr.h"
 #include "acl.h"
-#include "group.h"
 
 /*
  * ialloc.c contains the inodes allocation and deallocation routines
@@ -123,16 +122,16 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
                unlock_buffer(bh);
                return bh;
        }
-       spin_lock(sb_bgl_lock(EXT4_SB(sb), block_group));
+       ext4_lock_group(sb, block_group);
        if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
                ext4_init_inode_bitmap(sb, bh, block_group, desc);
                set_bitmap_uptodate(bh);
                set_buffer_uptodate(bh);
-               spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group));
+               ext4_unlock_group(sb, block_group);
                unlock_buffer(bh);
                return bh;
        }
-       spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group));
+       ext4_unlock_group(sb, block_group);
        if (buffer_uptodate(bh)) {
                /*
                 * if not uninit if bh is uptodate,
@@ -247,9 +246,8 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
                goto error_return;
 
        /* Ok, now we can actually update the inode bitmaps.. */
-       spin_lock(sb_bgl_lock(sbi, block_group));
-       cleared = ext4_clear_bit(bit, bitmap_bh->b_data);
-       spin_unlock(sb_bgl_lock(sbi, block_group));
+       cleared = ext4_clear_bit_atomic(ext4_group_lock_ptr(sb, block_group),
+                                       bit, bitmap_bh->b_data);
        if (!cleared)
                ext4_error(sb, "ext4_free_inode",
                           "bit already cleared for inode %lu", ino);
@@ -261,7 +259,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
                if (fatal) goto error_return;
 
                if (gdp) {
-                       spin_lock(sb_bgl_lock(sbi, block_group));
+                       ext4_lock_group(sb, block_group);
                        count = ext4_free_inodes_count(sb, gdp) + 1;
                        ext4_free_inodes_set(sb, gdp, count);
                        if (is_directory) {
@@ -277,7 +275,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
                        }
                        gdp->bg_checksum = ext4_group_desc_csum(sbi,
                                                        block_group, gdp);
-                       spin_unlock(sb_bgl_lock(sbi, block_group));
+                       ext4_unlock_group(sb, block_group);
                        percpu_counter_inc(&sbi->s_freeinodes_counter);
                        if (is_directory)
                                percpu_counter_dec(&sbi->s_dirs_counter);
@@ -316,7 +314,7 @@ error_return:
 static int find_group_dir(struct super_block *sb, struct inode *parent,
                                ext4_group_t *best_group)
 {
-       ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
+       ext4_group_t ngroups = ext4_get_groups_count(sb);
        unsigned int freei, avefreei;
        struct ext4_group_desc *desc, *best_desc = NULL;
        ext4_group_t group;
@@ -349,11 +347,10 @@ static int find_group_flex(struct super_block *sb, struct inode *parent,
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct ext4_group_desc *desc;
-       struct buffer_head *bh;
        struct flex_groups *flex_group = sbi->s_flex_groups;
        ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
        ext4_group_t parent_fbg_group = ext4_flex_group(sbi, parent_group);
-       ext4_group_t ngroups = sbi->s_groups_count;
+       ext4_group_t ngroups = ext4_get_groups_count(sb);
        int flex_size = ext4_flex_bg_size(sbi);
        ext4_group_t best_flex = parent_fbg_group;
        int blocks_per_flex = sbi->s_blocks_per_group * flex_size;
@@ -362,7 +359,7 @@ static int find_group_flex(struct super_block *sb, struct inode *parent,
        ext4_group_t n_fbg_groups;
        ext4_group_t i;
 
-       n_fbg_groups = (sbi->s_groups_count + flex_size - 1) >>
+       n_fbg_groups = (ngroups + flex_size - 1) >>
                sbi->s_log_groups_per_flex;
 
 find_close_to_parent:
@@ -404,7 +401,7 @@ find_close_to_parent:
 found_flexbg:
        for (i = best_flex * flex_size; i < ngroups &&
                     i < (best_flex + 1) * flex_size; i++) {
-               desc = ext4_get_group_desc(sb, i, &bh);
+               desc = ext4_get_group_desc(sb, i, NULL);
                if (ext4_free_inodes_count(sb, desc)) {
                        *best_group = i;
                        goto out;
@@ -478,20 +475,21 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
 {
        ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       ext4_group_t ngroups = sbi->s_groups_count;
+       ext4_group_t real_ngroups = ext4_get_groups_count(sb);
        int inodes_per_group = EXT4_INODES_PER_GROUP(sb);
        unsigned int freei, avefreei;
        ext4_fsblk_t freeb, avefreeb;
        unsigned int ndirs;
        int max_dirs, min_inodes;
        ext4_grpblk_t min_blocks;
-       ext4_group_t i, grp, g;
+       ext4_group_t i, grp, g, ngroups;
        struct ext4_group_desc *desc;
        struct orlov_stats stats;
        int flex_size = ext4_flex_bg_size(sbi);
 
+       ngroups = real_ngroups;
        if (flex_size > 1) {
-               ngroups = (ngroups + flex_size - 1) >>
+               ngroups = (real_ngroups + flex_size - 1) >>
                        sbi->s_log_groups_per_flex;
                parent_group >>= sbi->s_log_groups_per_flex;
        }
@@ -543,7 +541,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
                 */
                grp *= flex_size;
                for (i = 0; i < flex_size; i++) {
-                       if (grp+i >= sbi->s_groups_count)
+                       if (grp+i >= real_ngroups)
                                break;
                        desc = ext4_get_group_desc(sb, grp+i, NULL);
                        if (desc && ext4_free_inodes_count(sb, desc)) {
@@ -583,7 +581,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
        }
 
 fallback:
-       ngroups = sbi->s_groups_count;
+       ngroups = real_ngroups;
        avefreei = freei / ngroups;
 fallback_retry:
        parent_group = EXT4_I(parent)->i_block_group;
@@ -613,9 +611,8 @@ static int find_group_other(struct super_block *sb, struct inode *parent,
                            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;
+       ext4_group_t i, last, ngroups = ext4_get_groups_count(sb);
        struct ext4_group_desc *desc;
-       ext4_group_t i, last;
        int flex_size = ext4_flex_bg_size(EXT4_SB(sb));
 
        /*
@@ -708,10 +705,10 @@ static int find_group_other(struct super_block *sb, struct inode *parent,
 
 /*
  * claim the inode from the inode bitmap. If the group
- * is uninit we need to take the groups's sb_bgl_lock
+ * is uninit we need to take the groups's ext4_group_lock
  * and clear the uninit flag. The inode bitmap update
  * and group desc uninit flag clear should be done
- * after holding sb_bgl_lock so that ext4_read_inode_bitmap
+ * after holding ext4_group_lock so that ext4_read_inode_bitmap
  * doesn't race with the ext4_claim_inode
  */
 static int ext4_claim_inode(struct super_block *sb,
@@ -722,7 +719,7 @@ static int ext4_claim_inode(struct super_block *sb,
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL);
 
-       spin_lock(sb_bgl_lock(sbi, group));
+       ext4_lock_group(sb, group);
        if (ext4_set_bit(ino, inode_bitmap_bh->b_data)) {
                /* not a free inode */
                retval = 1;
@@ -731,7 +728,7 @@ static int ext4_claim_inode(struct super_block *sb,
        ino++;
        if ((group == 0 && ino < EXT4_FIRST_INO(sb)) ||
                        ino > EXT4_INODES_PER_GROUP(sb)) {
-               spin_unlock(sb_bgl_lock(sbi, group));
+               ext4_unlock_group(sb, group);
                ext4_error(sb, __func__,
                           "reserved inode or inode > inodes count - "
                           "block_group = %u, inode=%lu", group,
@@ -780,7 +777,7 @@ static int ext4_claim_inode(struct super_block *sb,
        }
        gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
 err_ret:
-       spin_unlock(sb_bgl_lock(sbi, group));
+       ext4_unlock_group(sb, group);
        return retval;
 }
 
@@ -799,11 +796,10 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
        struct super_block *sb;
        struct buffer_head *inode_bitmap_bh = NULL;
        struct buffer_head *group_desc_bh;
-       ext4_group_t group = 0;
+       ext4_group_t ngroups, group = 0;
        unsigned long ino = 0;
        struct inode *inode;
        struct ext4_group_desc *gdp = NULL;
-       struct ext4_super_block *es;
        struct ext4_inode_info *ei;
        struct ext4_sb_info *sbi;
        int ret2, err = 0;
@@ -818,15 +814,14 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
                return ERR_PTR(-EPERM);
 
        sb = dir->i_sb;
+       ngroups = ext4_get_groups_count(sb);
        trace_mark(ext4_request_inode, "dev %s dir %lu mode %d", sb->s_id,
                   dir->i_ino, mode);
        inode = new_inode(sb);
        if (!inode)
                return ERR_PTR(-ENOMEM);
        ei = EXT4_I(inode);
-
        sbi = EXT4_SB(sb);
-       es = sbi->s_es;
 
        if (sbi->s_log_groups_per_flex && test_opt(sb, OLDALLOC)) {
                ret2 = find_group_flex(sb, dir, &group);
@@ -856,7 +851,7 @@ got_group:
        if (ret2 == -1)
                goto out;
 
-       for (i = 0; i < sbi->s_groups_count; i++) {
+       for (i = 0; i < ngroups; i++) {
                err = -EIO;
 
                gdp = ext4_get_group_desc(sb, group, &group_desc_bh);
@@ -917,7 +912,7 @@ repeat_in_this_group:
                 * group descriptor metadata has not yet been updated.
                 * So we just go onto the next blockgroup.
                 */
-               if (++group == sbi->s_groups_count)
+               if (++group == ngroups)
                        group = 0;
        }
        err = -ENOSPC;
@@ -938,7 +933,7 @@ got:
                }
 
                free = 0;
-               spin_lock(sb_bgl_lock(sbi, group));
+               ext4_lock_group(sb, group);
                /* recheck and clear flag under lock if we still need to */
                if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
                        free = ext4_free_blocks_after_init(sb, group, gdp);
@@ -947,7 +942,7 @@ got:
                        gdp->bg_checksum = ext4_group_desc_csum(sbi, group,
                                                                gdp);
                }
-               spin_unlock(sb_bgl_lock(sbi, group));
+               ext4_unlock_group(sb, group);
 
                /* Don't need to dirty bitmap block if we didn't change it */
                if (free) {
@@ -1158,7 +1153,7 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
 {
        unsigned long desc_count;
        struct ext4_group_desc *gdp;
-       ext4_group_t i;
+       ext4_group_t i, ngroups = ext4_get_groups_count(sb);
 #ifdef EXT4FS_DEBUG
        struct ext4_super_block *es;
        unsigned long bitmap_count, x;
@@ -1168,7 +1163,7 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
        desc_count = 0;
        bitmap_count = 0;
        gdp = NULL;
-       for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
+       for (i = 0; i < ngroups; i++) {
                gdp = ext4_get_group_desc(sb, i, NULL);
                if (!gdp)
                        continue;
@@ -1190,7 +1185,7 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
        return desc_count;
 #else
        desc_count = 0;
-       for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
+       for (i = 0; i < ngroups; i++) {
                gdp = ext4_get_group_desc(sb, i, NULL);
                if (!gdp)
                        continue;
@@ -1205,9 +1200,9 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
 unsigned long ext4_count_dirs(struct super_block * sb)
 {
        unsigned long count = 0;
-       ext4_group_t i;
+       ext4_group_t i, ngroups = ext4_get_groups_count(sb);
 
-       for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
+       for (i = 0; i < ngroups; i++) {
                struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
                if (!gdp)
                        continue;
index 2a9ffd528dd1271e179a35322ce2e0a522f4d5b2..875db944b22f19889727ed0fcc2b4c60dd4043e4 100644 (file)
@@ -372,20 +372,21 @@ static int ext4_block_to_path(struct inode *inode,
 }
 
 static int __ext4_check_blockref(const char *function, struct inode *inode,
-                                __le32 *p, unsigned int max) {
-
-       unsigned int maxblocks = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es);
+                                __le32 *p, unsigned int max)
+{
        __le32 *bref = p;
+       unsigned int blk;
+
        while (bref < p+max) {
-               if (unlikely(le32_to_cpu(*bref) >= maxblocks)) {
+               blk = le32_to_cpu(*bref++);
+               if (blk && 
+                   unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb), 
+                                                   blk, 1))) {
                        ext4_error(inode->i_sb, function,
-                                  "block reference %u >= max (%u) "
-                                  "in inode #%lu, offset=%d",
-                                  le32_to_cpu(*bref), maxblocks,
-                                  inode->i_ino, (int)(bref-p));
+                                  "invalid block reference %u "
+                                  "in inode #%lu", blk, inode->i_ino);
                        return -EIO;
                }
-               bref++;
        }
        return 0;
 }
@@ -892,6 +893,10 @@ err_out:
 }
 
 /*
+ * The ext4_ind_get_blocks() function handles non-extents inodes
+ * (i.e., using the traditional indirect/double-indirect i_blocks
+ * scheme) for ext4_get_blocks().
+ *
  * Allocation strategy is simple: if we have to allocate something, we will
  * have to go the whole way to leaf. So let's do it before attaching anything
  * to tree, set linkage between the newborn blocks, write them if sync is
@@ -909,15 +914,16 @@ err_out:
  * return = 0, if plain lookup failed.
  * return < 0, error case.
  *
- *
- * Need to be called with
- * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system block
- * (ie, create is zero). Otherwise down_write(&EXT4_I(inode)->i_data_sem)
+ * The ext4_ind_get_blocks() function should be called with
+ * down_write(&EXT4_I(inode)->i_data_sem) if allocating filesystem
+ * blocks (i.e., flags has EXT4_GET_BLOCKS_CREATE set) or
+ * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system
+ * blocks.
  */
-static int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
+static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode,
                                  ext4_lblk_t iblock, unsigned int maxblocks,
                                  struct buffer_head *bh_result,
-                                 int create, int extend_disksize)
+                                 int flags)
 {
        int err = -EIO;
        ext4_lblk_t offsets[4];
@@ -927,14 +933,11 @@ static int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
        int indirect_blks;
        int blocks_to_boundary = 0;
        int depth;
-       struct ext4_inode_info *ei = EXT4_I(inode);
        int count = 0;
        ext4_fsblk_t first_block = 0;
-       loff_t disksize;
-
 
        J_ASSERT(!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL));
-       J_ASSERT(handle != NULL || create == 0);
+       J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0);
        depth = ext4_block_to_path(inode, iblock, offsets,
                                        &blocks_to_boundary);
 
@@ -963,7 +966,7 @@ static int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
        }
 
        /* Next simple case - plain lookup or failed read of indirect block */
-       if (!create || err == -EIO)
+       if ((flags & EXT4_GET_BLOCKS_CREATE) == 0 || err == -EIO)
                goto cleanup;
 
        /*
@@ -997,19 +1000,7 @@ static int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
        if (!err)
                err = ext4_splice_branch(handle, inode, iblock,
                                        partial, indirect_blks, count);
-       /*
-        * i_disksize growing is protected by i_data_sem.  Don't forget to
-        * protect it if you're about to implement concurrent
-        * ext4_get_block() -bzzz
-       */
-       if (!err && extend_disksize) {
-               disksize = ((loff_t) iblock + count) << inode->i_blkbits;
-               if (disksize > i_size_read(inode))
-                       disksize = i_size_read(inode);
-               if (disksize > ei->i_disksize)
-                       ei->i_disksize = disksize;
-       }
-       if (err)
+       else 
                goto cleanup;
 
        set_buffer_new(bh_result);
@@ -1120,8 +1111,23 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
                ext4_discard_preallocations(inode);
 }
 
+static int check_block_validity(struct inode *inode, sector_t logical,
+                               sector_t phys, int len)
+{
+       if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), phys, len)) {
+               ext4_error(inode->i_sb, "check_block_validity",
+                          "inode #%lu logical block %llu mapped to %llu "
+                          "(size %d)", inode->i_ino,
+                          (unsigned long long) logical,
+                          (unsigned long long) phys, len);
+               WARN_ON(1);
+               return -EIO;
+       }
+       return 0;
+}
+
 /*
- * The ext4_get_blocks_wrap() function try to look up the requested blocks,
+ * The ext4_get_blocks() function tries to look up the requested blocks,
  * and returns if the blocks are already mapped.
  *
  * Otherwise it takes the write lock of the i_data_sem and allocate blocks
@@ -1129,7 +1135,7 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
  * mapped.
  *
  * If file type is extents based, it will call ext4_ext_get_blocks(),
- * Otherwise, call with ext4_get_blocks_handle() to handle indirect mapping
+ * Otherwise, call with ext4_ind_get_blocks() to handle indirect mapping
  * based files
  *
  * On success, it returns the number of blocks being mapped or allocate.
@@ -1142,9 +1148,9 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
  *
  * It returns the error in case of allocation failure.
  */
-int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
-                       unsigned int max_blocks, struct buffer_head *bh,
-                       int create, int extend_disksize, int flag)
+int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
+                   unsigned int max_blocks, struct buffer_head *bh,
+                   int flags)
 {
        int retval;
 
@@ -1152,21 +1158,28 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
        clear_buffer_unwritten(bh);
 
        /*
-        * Try to see if we can get  the block without requesting
-        * for new file system block.
+        * Try to see if we can get the block without requesting a new
+        * file system block.
         */
        down_read((&EXT4_I(inode)->i_data_sem));
        if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
                retval =  ext4_ext_get_blocks(handle, inode, block, max_blocks,
-                               bh, 0, 0);
+                               bh, 0);
        } else {
-               retval = ext4_get_blocks_handle(handle,
-                               inode, block, max_blocks, bh, 0, 0);
+               retval = ext4_ind_get_blocks(handle, inode, block, max_blocks,
+                                            bh, 0);
        }
        up_read((&EXT4_I(inode)->i_data_sem));
 
+       if (retval > 0 && buffer_mapped(bh)) {
+               int ret = check_block_validity(inode, block, 
+                                              bh->b_blocknr, retval);
+               if (ret != 0)
+                       return ret;
+       }
+
        /* If it is only a block(s) look up */
-       if (!create)
+       if ((flags & EXT4_GET_BLOCKS_CREATE) == 0)
                return retval;
 
        /*
@@ -1205,7 +1218,7 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
         * let the underlying get_block() function know to
         * avoid double accounting
         */
-       if (flag)
+       if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)
                EXT4_I(inode)->i_delalloc_reserved_flag = 1;
        /*
         * We need to check for EXT4 here because migrate
@@ -1213,10 +1226,10 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
         */
        if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
                retval =  ext4_ext_get_blocks(handle, inode, block, max_blocks,
-                               bh, create, extend_disksize);
+                                             bh, flags);
        } else {
-               retval = ext4_get_blocks_handle(handle, inode, block,
-                               max_blocks, bh, create, extend_disksize);
+               retval = ext4_ind_get_blocks(handle, inode, block,
+                                            max_blocks, bh, flags);
 
                if (retval > 0 && buffer_new(bh)) {
                        /*
@@ -1229,18 +1242,23 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
                }
        }
 
-       if (flag) {
+       if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)
                EXT4_I(inode)->i_delalloc_reserved_flag = 0;
-               /*
-                * Update reserved blocks/metadata blocks
-                * after successful block allocation
-                * which were deferred till now
-                */
-               if ((retval > 0) && buffer_delay(bh))
-                       ext4_da_update_reserve_space(inode, retval);
-       }
+
+       /*
+        * Update reserved blocks/metadata blocks after successful
+        * block allocation which had been deferred till now.
+        */
+       if ((retval > 0) && (flags & EXT4_GET_BLOCKS_UPDATE_RESERVE_SPACE))
+               ext4_da_update_reserve_space(inode, retval);
 
        up_write((&EXT4_I(inode)->i_data_sem));
+       if (retval > 0 && buffer_mapped(bh)) {
+               int ret = check_block_validity(inode, block, 
+                                              bh->b_blocknr, retval);
+               if (ret != 0)
+                       return ret;
+       }
        return retval;
 }
 
@@ -1268,8 +1286,8 @@ int ext4_get_block(struct inode *inode, sector_t iblock,
                started = 1;
        }
 
-       ret = ext4_get_blocks_wrap(handle, inode, iblock,
-                                       max_blocks, bh_result, create, 0, 0);
+       ret = ext4_get_blocks(handle, inode, iblock, max_blocks, bh_result,
+                             create ? EXT4_GET_BLOCKS_CREATE : 0);
        if (ret > 0) {
                bh_result->b_size = (ret << inode->i_blkbits);
                ret = 0;
@@ -1288,17 +1306,19 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
 {
        struct buffer_head dummy;
        int fatal = 0, err;
+       int flags = 0;
 
        J_ASSERT(handle != NULL || create == 0);
 
        dummy.b_state = 0;
        dummy.b_blocknr = -1000;
        buffer_trace_init(&dummy.b_history);
-       err = ext4_get_blocks_wrap(handle, inode, block, 1,
-                                       &dummy, create, 1, 0);
+       if (create)
+               flags |= EXT4_GET_BLOCKS_CREATE;
+       err = ext4_get_blocks(handle, inode, block, 1, &dummy, flags);
        /*
-        * ext4_get_blocks_handle() returns number of blocks
-        * mapped. 0 in case of a HOLE.
+        * ext4_get_blocks() returns number of blocks mapped. 0 in
+        * case of a HOLE.
         */
        if (err > 0) {
                if (err > 1)
@@ -1439,7 +1459,7 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
                                struct page **pagep, void **fsdata)
 {
        struct inode *inode = mapping->host;
-       int ret, needed_blocks = ext4_writepage_trans_blocks(inode);
+       int ret, needed_blocks;
        handle_t *handle;
        int retries = 0;
        struct page *page;
@@ -1450,6 +1470,11 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
                   "dev %s ino %lu pos %llu len %u flags %u",
                   inode->i_sb->s_id, inode->i_ino,
                   (unsigned long long) pos, len, flags);
+       /*
+        * Reserve one block more for addition to orphan list in case
+        * we allocate blocks but write fails for some reason
+        */
+       needed_blocks = ext4_writepage_trans_blocks(inode) + 1;
        index = pos >> PAGE_CACHE_SHIFT;
        from = pos & (PAGE_CACHE_SIZE - 1);
        to = from + len;
@@ -1483,15 +1508,30 @@ retry:
 
        if (ret) {
                unlock_page(page);
-               ext4_journal_stop(handle);
                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)
+                       ext4_orphan_add(handle, inode);
+
+               ext4_journal_stop(handle);
+               if (pos + len > inode->i_size) {
                        vmtruncate(inode, inode->i_size);
+                       /* 
+                        * If vmtruncate failed early the inode might
+                        * still be on the orphan list; we need to
+                        * make sure the inode is removed from the
+                        * orphan list in that case.
+                        */
+                       if (inode->i_nlink)
+                               ext4_orphan_del(NULL, inode);
+               }
        }
 
        if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
@@ -1509,6 +1549,52 @@ static int write_end_fn(handle_t *handle, struct buffer_head *bh)
        return ext4_handle_dirty_metadata(handle, NULL, bh);
 }
 
+static int ext4_generic_write_end(struct file *file,
+                               struct address_space *mapping,
+                               loff_t pos, unsigned len, unsigned copied,
+                               struct page *page, void *fsdata)
+{
+       int i_size_changed = 0;
+       struct inode *inode = mapping->host;
+       handle_t *handle = ext4_journal_current_handle();
+
+       copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
+
+       /*
+        * No need to use i_size_read() here, the i_size
+        * cannot change under us because we hold i_mutex.
+        *
+        * But it's important to update i_size while still holding page lock:
+        * page writeout could otherwise come in and zero beyond i_size.
+        */
+       if (pos + copied > inode->i_size) {
+               i_size_write(inode, pos + copied);
+               i_size_changed = 1;
+       }
+
+       if (pos + copied >  EXT4_I(inode)->i_disksize) {
+               /* We need to mark inode dirty even if
+                * new_i_size is less that inode->i_size
+                * bu greater than i_disksize.(hint delalloc)
+                */
+               ext4_update_i_disksize(inode, (pos + copied));
+               i_size_changed = 1;
+       }
+       unlock_page(page);
+       page_cache_release(page);
+
+       /*
+        * Don't mark the inode dirty under page lock. First, it unnecessarily
+        * makes the holding time of page lock longer. Second, it forces lock
+        * ordering of page lock and transaction start for journaling
+        * filesystems.
+        */
+       if (i_size_changed)
+               ext4_mark_inode_dirty(handle, inode);
+
+       return copied;
+}
+
 /*
  * We need to pick up the new inode size which generic_commit_write gave us
  * `file' can be NULL - eg, when called from page_symlink().
@@ -1532,21 +1618,15 @@ static int ext4_ordered_write_end(struct file *file,
        ret = ext4_jbd2_file_inode(handle, inode);
 
        if (ret == 0) {
-               loff_t new_i_size;
-
-               new_i_size = pos + copied;
-               if (new_i_size > EXT4_I(inode)->i_disksize) {
-                       ext4_update_i_disksize(inode, new_i_size);
-                       /* We need to mark inode dirty even if
-                        * new_i_size is less that inode->i_size
-                        * bu greater than i_disksize.(hint delalloc)
-                        */
-                       ext4_mark_inode_dirty(handle, inode);
-               }
-
-               ret2 = generic_write_end(file, mapping, pos, len, copied,
+               ret2 = ext4_generic_write_end(file, mapping, pos, len, copied,
                                                        page, fsdata);
                copied = ret2;
+               if (pos + len > inode->i_size)
+                       /* if we have allocated more blocks and copied
+                        * less. We will have blocks allocated outside
+                        * inode->i_size. So truncate them
+                        */
+                       ext4_orphan_add(handle, inode);
                if (ret2 < 0)
                        ret = ret2;
        }
@@ -1554,6 +1634,18 @@ static int ext4_ordered_write_end(struct file *file,
        if (!ret)
                ret = ret2;
 
+       if (pos + len > inode->i_size) {
+               vmtruncate(inode, inode->i_size);
+               /* 
+                * If vmtruncate failed early the inode might still be
+                * on the orphan list; we need to make sure the inode
+                * is removed from the orphan list in that case.
+                */
+               if (inode->i_nlink)
+                       ext4_orphan_del(NULL, inode);
+       }
+
+
        return ret ? ret : copied;
 }
 
@@ -1565,25 +1657,21 @@ static int ext4_writeback_write_end(struct file *file,
        handle_t *handle = ext4_journal_current_handle();
        struct inode *inode = mapping->host;
        int ret = 0, ret2;
-       loff_t new_i_size;
 
        trace_mark(ext4_writeback_write_end,
                   "dev %s ino %lu pos %llu len %u copied %u",
                   inode->i_sb->s_id, inode->i_ino,
                   (unsigned long long) pos, len, copied);
-       new_i_size = pos + copied;
-       if (new_i_size > EXT4_I(inode)->i_disksize) {
-               ext4_update_i_disksize(inode, new_i_size);
-               /* We need to mark inode dirty even if
-                * new_i_size is less that inode->i_size
-                * bu greater than i_disksize.(hint delalloc)
-                */
-               ext4_mark_inode_dirty(handle, inode);
-       }
-
-       ret2 = generic_write_end(file, mapping, pos, len, copied,
+       ret2 = ext4_generic_write_end(file, mapping, pos, len, copied,
                                                        page, fsdata);
        copied = ret2;
+       if (pos + len > inode->i_size)
+               /* if we have allocated more blocks and copied
+                * less. We will have blocks allocated outside
+                * inode->i_size. So truncate them
+                */
+               ext4_orphan_add(handle, inode);
+
        if (ret2 < 0)
                ret = ret2;
 
@@ -1591,6 +1679,17 @@ static int ext4_writeback_write_end(struct file *file,
        if (!ret)
                ret = ret2;
 
+       if (pos + len > inode->i_size) {
+               vmtruncate(inode, inode->i_size);
+               /* 
+                * If vmtruncate failed early the inode might still be
+                * on the orphan list; we need to make sure the inode
+                * is removed from the orphan list in that case.
+                */
+               if (inode->i_nlink)
+                       ext4_orphan_del(NULL, inode);
+       }
+
        return ret ? ret : copied;
 }
 
@@ -1635,10 +1734,27 @@ static int ext4_journalled_write_end(struct file *file,
        }
 
        unlock_page(page);
+       page_cache_release(page);
+       if (pos + len > inode->i_size)
+               /* if we have allocated more blocks and copied
+                * less. We will have blocks allocated outside
+                * inode->i_size. So truncate them
+                */
+               ext4_orphan_add(handle, inode);
+
        ret2 = ext4_journal_stop(handle);
        if (!ret)
                ret = ret2;
-       page_cache_release(page);
+       if (pos + len > inode->i_size) {
+               vmtruncate(inode, inode->i_size);
+               /* 
+                * If vmtruncate failed early the inode might still be
+                * on the orphan list; we need to make sure the inode
+                * is removed from the orphan list in that case.
+                */
+               if (inode->i_nlink)
+                       ext4_orphan_del(NULL, inode);
+       }
 
        return ret ? ret : copied;
 }
@@ -1852,7 +1968,7 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd)
  * @logical - first logical block to start assignment with
  *
  * the function goes through all passed space and put actual disk
- * block numbers into buffer heads, dropping BH_Delay
+ * block numbers into buffer heads, dropping BH_Delay and BH_Unwritten
  */
 static void mpage_put_bnr_to_bhs(struct mpage_da_data *mpd, sector_t logical,
                                 struct buffer_head *exbh)
@@ -1902,16 +2018,24 @@ static void mpage_put_bnr_to_bhs(struct mpage_da_data *mpd, sector_t logical,
                        do {
                                if (cur_logical >= logical + blocks)
                                        break;
-                               if (buffer_delay(bh)) {
-                                       bh->b_blocknr = pblock;
-                                       clear_buffer_delay(bh);
-                                       bh->b_bdev = inode->i_sb->s_bdev;
-                               } else if (buffer_unwritten(bh)) {
-                                       bh->b_blocknr = pblock;
-                                       clear_buffer_unwritten(bh);
-                                       set_buffer_mapped(bh);
-                                       set_buffer_new(bh);
-                                       bh->b_bdev = inode->i_sb->s_bdev;
+
+                               if (buffer_delay(bh) ||
+                                               buffer_unwritten(bh)) {
+
+                                       BUG_ON(bh->b_bdev != inode->i_sb->s_bdev);
+
+                                       if (buffer_delay(bh)) {
+                                               clear_buffer_delay(bh);
+                                               bh->b_blocknr = pblock;
+                                       } else {
+                                               /*
+                                                * unwritten already should have
+                                                * blocknr assigned. Verify that
+                                                */
+                                               clear_buffer_unwritten(bh);
+                                               BUG_ON(bh->b_blocknr != pblock);
+                                       }
+
                                } else if (buffer_mapped(bh))
                                        BUG_ON(bh->b_blocknr != pblock);
 
@@ -1990,51 +2114,6 @@ 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
  *
@@ -2045,29 +2124,57 @@ static int ext4_da_get_block_write(struct inode *inode, sector_t iblock,
  */
 static int mpage_da_map_blocks(struct mpage_da_data *mpd)
 {
-       int err = 0;
+       int err, blks, get_blocks_flags;
        struct buffer_head new;
-       sector_t next;
+       sector_t next = mpd->b_blocknr;
+       unsigned max_blocks = mpd->b_size >> mpd->inode->i_blkbits;
+       loff_t disksize = EXT4_I(mpd->inode)->i_disksize;
+       handle_t *handle = NULL;
 
        /*
         * We consider only non-mapped and non-allocated blocks
         */
        if ((mpd->b_state  & (1 << BH_Mapped)) &&
-           !(mpd->b_state & (1 << BH_Delay)))
+               !(mpd->b_state & (1 << BH_Delay)) &&
+               !(mpd->b_state & (1 << BH_Unwritten)))
                return 0;
-       new.b_state = mpd->b_state;
-       new.b_blocknr = 0;
-       new.b_size = mpd->b_size;
-       next = mpd->b_blocknr;
+
        /*
-        * If we didn't accumulate anything
-        * to write simply return
+        * If we didn't accumulate anything to write simply return
         */
-       if (!new.b_size)
+       if (!mpd->b_size)
                return 0;
 
-       err = ext4_da_get_block_write(mpd->inode, next, &new, 1);
-       if (err) {
+       handle = ext4_journal_current_handle();
+       BUG_ON(!handle);
+
+       /*
+        * Call ext4_get_blocks() to allocate any delayed allocation
+        * blocks, or to convert an uninitialized extent to be
+        * initialized (in the case where we have written into
+        * one or more preallocated blocks).
+        *
+        * We pass in the magic EXT4_GET_BLOCKS_DELALLOC_RESERVE to
+        * indicate that we are on the delayed allocation path.  This
+        * affects functions in many different parts of the allocation
+        * call path.  This flag exists primarily because we don't
+        * want to change *many* call functions, so ext4_get_blocks()
+        * will set the magic i_delalloc_reserved_flag once the
+        * inode's allocation semaphore is taken.
+        *
+        * If the blocks in questions were delalloc blocks, set
+        * EXT4_GET_BLOCKS_DELALLOC_RESERVE so the delalloc accounting
+        * variables are updated after the blocks have been allocated.
+        */
+       new.b_state = 0;
+       get_blocks_flags = (EXT4_GET_BLOCKS_CREATE |
+                           EXT4_GET_BLOCKS_DELALLOC_RESERVE);
+       if (mpd->b_state & (1 << BH_Delay))
+               get_blocks_flags |= EXT4_GET_BLOCKS_UPDATE_RESERVE_SPACE;
+       blks = ext4_get_blocks(handle, mpd->inode, next, max_blocks,
+                              &new, get_blocks_flags);
+       if (blks < 0) {
+               err = blks;
                /*
                 * If get block returns with error we simply
                 * return. Later writepage will redirty the page and
@@ -2100,12 +2207,14 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
                if (err == -ENOSPC) {
                        ext4_print_free_blocks(mpd->inode);
                }
-               /* invlaidate all the pages */
+               /* invalidate all the pages */
                ext4_da_block_invalidatepages(mpd, next,
                                mpd->b_size >> mpd->inode->i_blkbits);
                return err;
        }
-       BUG_ON(new.b_size == 0);
+       BUG_ON(blks == 0);
+
+       new.b_size = (blks << mpd->inode->i_blkbits);
 
        if (buffer_new(&new))
                __unmap_underlying_blocks(mpd->inode, &new);
@@ -2118,6 +2227,23 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
            (mpd->b_state & (1 << BH_Unwritten)))
                mpage_put_bnr_to_bhs(mpd, next, &new);
 
+       if (ext4_should_order_data(mpd->inode)) {
+               err = ext4_jbd2_file_inode(handle, mpd->inode);
+               if (err)
+                       return err;
+       }
+
+       /*
+        * Update on-disk size along with block allocation.
+        */
+       disksize = ((loff_t) next + blks) << mpd->inode->i_blkbits;
+       if (disksize > i_size_read(mpd->inode))
+               disksize = i_size_read(mpd->inode);
+       if (disksize > EXT4_I(mpd->inode)->i_disksize) {
+               ext4_update_i_disksize(mpd->inode, disksize);
+               return ext4_mark_inode_dirty(handle, mpd->inode);
+       }
+
        return 0;
 }
 
@@ -2192,6 +2318,17 @@ flush_it:
        return;
 }
 
+static int ext4_bh_unmapped_or_delay(handle_t *handle, struct buffer_head *bh)
+{
+       /*
+        * unmapped buffer is possible for holes.
+        * delay buffer is possible with delayed allocation.
+        * We also need to consider unwritten buffer as unmapped.
+        */
+       return (!buffer_mapped(bh) || buffer_delay(bh) ||
+                               buffer_unwritten(bh)) && buffer_dirty(bh);
+}
+
 /*
  * __mpage_da_writepage - finds extent of pages and blocks
  *
@@ -2276,8 +2413,7 @@ static int __mpage_da_writepage(struct page *page,
                         * Otherwise we won't make progress
                         * with the page in ext4_da_writepage
                         */
-                       if (buffer_dirty(bh) &&
-                           (!buffer_mapped(bh) || buffer_delay(bh))) {
+                       if (ext4_bh_unmapped_or_delay(NULL, bh)) {
                                mpage_add_bh_to_extent(mpd, logical,
                                                       bh->b_size,
                                                       bh->b_state);
@@ -2303,8 +2439,16 @@ static int __mpage_da_writepage(struct page *page,
 }
 
 /*
- * this is a special callback for ->write_begin() only
- * it's intention is to return mapped block or reserve space
+ * This is a special get_blocks_t callback which is used by
+ * ext4_da_write_begin().  It will either return mapped block or
+ * reserve space for a single block.
+ *
+ * For delayed buffer_head we have BH_Mapped, BH_New, BH_Delay set.
+ * We also have b_blocknr = -1 and b_bdev initialized properly
+ *
+ * For unwritten buffer_head we have BH_Mapped, BH_New, BH_Unwritten set.
+ * We also have b_blocknr = physicalblock mapping unwritten extent and b_bdev
+ * initialized properly.
  */
 static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
                                  struct buffer_head *bh_result, int create)
@@ -2323,7 +2467,7 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
         * preallocated blocks are unmapped but should treated
         * the same as allocated blocks.
         */
-       ret = ext4_get_blocks_wrap(NULL, inode, iblock, 1,  bh_result, 0, 0, 0);
+       ret = ext4_get_blocks(NULL, inode, iblock, 1,  bh_result, 0);
        if ((ret == 0) && !buffer_delay(bh_result)) {
                /* the block isn't (pre)allocated yet, let's reserve space */
                /*
@@ -2340,40 +2484,53 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
                set_buffer_delay(bh_result);
        } else if (ret > 0) {
                bh_result->b_size = (ret << inode->i_blkbits);
-               /*
-                * With sub-block writes into unwritten extents
-                * we also need to mark the buffer as new so that
-                * the unwritten parts of the buffer gets correctly zeroed.
-                */
-               if (buffer_unwritten(bh_result))
+               if (buffer_unwritten(bh_result)) {
+                       /* A delayed write to unwritten bh should
+                        * be marked new and mapped.  Mapped ensures
+                        * that we don't do get_block multiple times
+                        * when we write to the same offset and new
+                        * ensures that we do proper zero out for
+                        * partial write.
+                        */
                        set_buffer_new(bh_result);
+                       set_buffer_mapped(bh_result);
+               }
                ret = 0;
        }
 
        return ret;
 }
 
-static int ext4_bh_unmapped_or_delay(handle_t *handle, struct buffer_head *bh)
-{
-       /*
-        * unmapped buffer is possible for holes.
-        * delay buffer is possible with delayed allocation
-        */
-       return ((!buffer_mapped(bh) || buffer_delay(bh)) && buffer_dirty(bh));
-}
-
-static int ext4_normal_get_block_write(struct inode *inode, sector_t iblock,
+/*
+ * This function is used as a standard get_block_t calback function
+ * when there is no desire to allocate any blocks.  It is used as a
+ * callback function for block_prepare_write(), nobh_writepage(), and
+ * block_write_full_page().  These functions should only try to map a
+ * single block at a time.
+ *
+ * Since this function doesn't do block allocations even if the caller
+ * requests it by passing in create=1, it is critically important that
+ * any caller checks to make sure that any buffer heads are returned
+ * by this function are either all already mapped or marked for
+ * delayed allocation before calling nobh_writepage() or
+ * block_write_full_page().  Otherwise, b_blocknr could be left
+ * unitialized, and the page write functions will be taken by
+ * surprise.
+ */
+static int noalloc_get_block_write(struct inode *inode, sector_t iblock,
                                   struct buffer_head *bh_result, int create)
 {
        int ret = 0;
        unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
 
+       BUG_ON(bh_result->b_size != inode->i_sb->s_blocksize);
+
        /*
         * we don't want to do block allocation in writepage
         * so call get_block_wrap with create = 0
         */
-       ret = ext4_get_blocks_wrap(NULL, inode, iblock, max_blocks,
-                                  bh_result, 0, 0, 0);
+       ret = ext4_get_blocks(NULL, inode, iblock, max_blocks, bh_result, 0);
+       BUG_ON(create && ret == 0);
        if (ret > 0) {
                bh_result->b_size = (ret << inode->i_blkbits);
                ret = 0;
@@ -2382,10 +2539,11 @@ static int ext4_normal_get_block_write(struct inode *inode, sector_t iblock,
 }
 
 /*
- * get called vi ext4_da_writepages after taking page lock (have journal handle)
- * get called via journal_submit_inode_data_buffers (no journal handle)
- * get called via shrink_page_list via pdflush (no journal handle)
- * or grab_page_cache when doing write_begin (have journal handle)
+ * This function can get called via...
+ *   - ext4_da_writepages after taking page lock (have journal handle)
+ *   - journal_submit_inode_data_buffers (no journal handle)
+ *   - shrink_page_list via pdflush (no journal handle)
+ *   - grab_page_cache when doing write_begin (have journal handle)
  */
 static int ext4_da_writepage(struct page *page,
                                struct writeback_control *wbc)
@@ -2436,7 +2594,7 @@ static int ext4_da_writepage(struct page *page,
                 * do block allocation here.
                 */
                ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
-                                               ext4_normal_get_block_write);
+                                         noalloc_get_block_write);
                if (!ret) {
                        page_bufs = page_buffers(page);
                        /* check whether all are mapped and non delay */
@@ -2461,11 +2619,10 @@ static int ext4_da_writepage(struct page *page,
        }
 
        if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
-               ret = nobh_writepage(page, ext4_normal_get_block_write, wbc);
+               ret = nobh_writepage(page, noalloc_get_block_write, wbc);
        else
-               ret = block_write_full_page(page,
-                                               ext4_normal_get_block_write,
-                                               wbc);
+               ret = block_write_full_page(page, noalloc_get_block_write,
+                                           wbc);
 
        return ret;
 }
@@ -2777,7 +2934,7 @@ retry:
        *pagep = page;
 
        ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                                                       ext4_da_get_block_prep);
+                               ext4_da_get_block_prep);
        if (ret < 0) {
                unlock_page(page);
                ext4_journal_stop(handle);
@@ -2815,7 +2972,7 @@ static int ext4_da_should_update_i_disksize(struct page *page,
        for (i = 0; i < idx; i++)
                bh = bh->b_this_page;
 
-       if (!buffer_mapped(bh) || (buffer_delay(bh)))
+       if (!buffer_mapped(bh) || (buffer_delay(bh)) || buffer_unwritten(bh))
                return 0;
        return 1;
 }
@@ -3085,12 +3242,10 @@ static int __ext4_normal_writepage(struct page *page,
        struct inode *inode = page->mapping->host;
 
        if (test_opt(inode->i_sb, NOBH))
-               return nobh_writepage(page,
-                                       ext4_normal_get_block_write, wbc);
+               return nobh_writepage(page, noalloc_get_block_write, wbc);
        else
-               return block_write_full_page(page,
-                                               ext4_normal_get_block_write,
-                                               wbc);
+               return block_write_full_page(page, noalloc_get_block_write,
+                                            wbc);
 }
 
 static int ext4_normal_writepage(struct page *page,
@@ -3142,7 +3297,7 @@ static int __ext4_journalled_writepage(struct page *page,
        int err;
 
        ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
-                                       ext4_normal_get_block_write);
+                                 noalloc_get_block_write);
        if (ret != 0)
                goto out_unlock;
 
@@ -3227,9 +3382,8 @@ static int ext4_journalled_writepage(struct page *page,
                 * really know unless we go poke around in the buffer_heads.
                 * But block_write_full_page will do the right thing.
                 */
-               return block_write_full_page(page,
-                                               ext4_normal_get_block_write,
-                                               wbc);
+               return block_write_full_page(page, noalloc_get_block_write,
+                                            wbc);
        }
 no_write:
        redirty_page_for_writepage(wbc, page);
@@ -3973,7 +4127,8 @@ 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))
+       if (ei->i_disksize && 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) {
@@ -4715,25 +4870,6 @@ int ext4_write_inode(struct inode *inode, int wait)
        return ext4_force_commit(inode->i_sb);
 }
 
-int __ext4_write_dirty_metadata(struct inode *inode, struct buffer_head *bh)
-{
-       int err = 0;
-
-       mark_buffer_dirty(bh);
-       if (inode && inode_needs_sync(inode)) {
-               sync_dirty_buffer(bh);
-               if (buffer_req(bh) && !buffer_uptodate(bh)) {
-                       ext4_error(inode->i_sb, __func__,
-                                  "IO error syncing inode, "
-                                  "inode=%lu, block=%llu",
-                                  inode->i_ino,
-                                  (unsigned long long)bh->b_blocknr);
-                       err = -EIO;
-               }
-       }
-       return err;
-}
-
 /*
  * ext4_setattr()
  *
@@ -4930,7 +5066,8 @@ static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk)
  */
 int ext4_meta_trans_blocks(struct inode *inode, int nrblocks, int chunk)
 {
-       int groups, gdpblocks;
+       ext4_group_t groups, ngroups = ext4_get_groups_count(inode->i_sb);
+       int gdpblocks;
        int idxblocks;
        int ret = 0;
 
@@ -4957,8 +5094,8 @@ int ext4_meta_trans_blocks(struct inode *inode, int nrblocks, int chunk)
                groups += nrblocks;
 
        gdpblocks = groups;
-       if (groups > EXT4_SB(inode->i_sb)->s_groups_count)
-               groups = EXT4_SB(inode->i_sb)->s_groups_count;
+       if (groups > ngroups)
+               groups = ngroups;
        if (groups > EXT4_SB(inode->i_sb)->s_gdb_count)
                gdpblocks = EXT4_SB(inode->i_sb)->s_gdb_count;
 
@@ -4998,7 +5135,7 @@ int ext4_writepage_trans_blocks(struct inode *inode)
  * Calculate the journal credits for a chunk of data modification.
  *
  * This is called from DIO, fallocate or whoever calling
- * ext4_get_blocks_wrap() to map/allocate a chunk of contigous disk blocks.
+ * ext4_get_blocks() to map/allocate a chunk of contigous disk blocks.
  *
  * journal buffers for data blocks are not included here, as DIO
  * and fallocate do no need to journal data buffers.
index f871677a798499c4327629cf282d4f75b38d44b3..ed8482e22c0ea7623641c28efbede7bb7b65091e 100644 (file)
@@ -372,24 +372,12 @@ static inline void mb_set_bit(int bit, void *addr)
        ext4_set_bit(bit, addr);
 }
 
-static inline void mb_set_bit_atomic(spinlock_t *lock, int bit, void *addr)
-{
-       addr = mb_correct_addr_and_bit(&bit, addr);
-       ext4_set_bit_atomic(lock, bit, addr);
-}
-
 static inline void mb_clear_bit(int bit, void *addr)
 {
        addr = mb_correct_addr_and_bit(&bit, addr);
        ext4_clear_bit(bit, addr);
 }
 
-static inline void mb_clear_bit_atomic(spinlock_t *lock, int bit, void *addr)
-{
-       addr = mb_correct_addr_and_bit(&bit, addr);
-       ext4_clear_bit_atomic(lock, bit, addr);
-}
-
 static inline int mb_find_next_zero_bit(void *addr, int max, int start)
 {
        int fix = 0, ret, tmpmax;
@@ -448,7 +436,7 @@ static void mb_free_blocks_double(struct inode *inode, struct ext4_buddy *e4b,
 
        if (unlikely(e4b->bd_info->bb_bitmap == NULL))
                return;
-       BUG_ON(!ext4_is_group_locked(sb, e4b->bd_group));
+       assert_spin_locked(ext4_group_lock_ptr(sb, e4b->bd_group));
        for (i = 0; i < count; i++) {
                if (!mb_test_bit(first + i, e4b->bd_info->bb_bitmap)) {
                        ext4_fsblk_t blocknr;
@@ -472,7 +460,7 @@ static void mb_mark_used_double(struct ext4_buddy *e4b, int first, int count)
 
        if (unlikely(e4b->bd_info->bb_bitmap == NULL))
                return;
-       BUG_ON(!ext4_is_group_locked(e4b->bd_sb, e4b->bd_group));
+       assert_spin_locked(ext4_group_lock_ptr(e4b->bd_sb, e4b->bd_group));
        for (i = 0; i < count; i++) {
                BUG_ON(mb_test_bit(first + i, e4b->bd_info->bb_bitmap));
                mb_set_bit(first + i, e4b->bd_info->bb_bitmap);
@@ -739,6 +727,7 @@ static void ext4_mb_generate_buddy(struct super_block *sb,
 
 static int ext4_mb_init_cache(struct page *page, char *incore)
 {
+       ext4_group_t ngroups;
        int blocksize;
        int blocks_per_page;
        int groups_per_page;
@@ -757,6 +746,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
 
        inode = page->mapping->host;
        sb = inode->i_sb;
+       ngroups = ext4_get_groups_count(sb);
        blocksize = 1 << inode->i_blkbits;
        blocks_per_page = PAGE_CACHE_SIZE / blocksize;
 
@@ -780,7 +770,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
        for (i = 0; i < groups_per_page; i++) {
                struct ext4_group_desc *desc;
 
-               if (first_group + i >= EXT4_SB(sb)->s_groups_count)
+               if (first_group + i >= ngroups)
                        break;
 
                err = -EIO;
@@ -801,17 +791,17 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                        unlock_buffer(bh[i]);
                        continue;
                }
-               spin_lock(sb_bgl_lock(EXT4_SB(sb), first_group + i));
+               ext4_lock_group(sb, first_group + i);
                if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
                        ext4_init_block_bitmap(sb, bh[i],
                                                first_group + i, desc);
                        set_bitmap_uptodate(bh[i]);
                        set_buffer_uptodate(bh[i]);
-                       spin_unlock(sb_bgl_lock(EXT4_SB(sb), first_group + i));
+                       ext4_unlock_group(sb, first_group + i);
                        unlock_buffer(bh[i]);
                        continue;
                }
-               spin_unlock(sb_bgl_lock(EXT4_SB(sb), first_group + i));
+               ext4_unlock_group(sb, first_group + i);
                if (buffer_uptodate(bh[i])) {
                        /*
                         * if not uninit if bh is uptodate,
@@ -852,7 +842,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                struct ext4_group_info *grinfo;
 
                group = (first_block + i) >> 1;
-               if (group >= EXT4_SB(sb)->s_groups_count)
+               if (group >= ngroups)
                        break;
 
                /*
@@ -1078,7 +1068,7 @@ static int mb_find_order_for_block(struct ext4_buddy *e4b, int block)
        return 0;
 }
 
-static void mb_clear_bits(spinlock_t *lock, void *bm, int cur, int len)
+static void mb_clear_bits(void *bm, int cur, int len)
 {
        __u32 *addr;
 
@@ -1091,15 +1081,12 @@ static void mb_clear_bits(spinlock_t *lock, void *bm, int cur, int len)
                        cur += 32;
                        continue;
                }
-               if (lock)
-                       mb_clear_bit_atomic(lock, cur, bm);
-               else
-                       mb_clear_bit(cur, bm);
+               mb_clear_bit(cur, bm);
                cur++;
        }
 }
 
-static void mb_set_bits(spinlock_t *lock, void *bm, int cur, int len)
+static void mb_set_bits(void *bm, int cur, int len)
 {
        __u32 *addr;
 
@@ -1112,10 +1099,7 @@ static void mb_set_bits(spinlock_t *lock, void *bm, int cur, int len)
                        cur += 32;
                        continue;
                }
-               if (lock)
-                       mb_set_bit_atomic(lock, cur, bm);
-               else
-                       mb_set_bit(cur, bm);
+               mb_set_bit(cur, bm);
                cur++;
        }
 }
@@ -1131,7 +1115,7 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
        struct super_block *sb = e4b->bd_sb;
 
        BUG_ON(first + count > (sb->s_blocksize << 3));
-       BUG_ON(!ext4_is_group_locked(sb, e4b->bd_group));
+       assert_spin_locked(ext4_group_lock_ptr(sb, e4b->bd_group));
        mb_check_buddy(e4b);
        mb_free_blocks_double(inode, e4b, first, count);
 
@@ -1212,7 +1196,7 @@ static int mb_find_extent(struct ext4_buddy *e4b, int order, int block,
        int ord;
        void *buddy;
 
-       BUG_ON(!ext4_is_group_locked(e4b->bd_sb, e4b->bd_group));
+       assert_spin_locked(ext4_group_lock_ptr(e4b->bd_sb, e4b->bd_group));
        BUG_ON(ex == NULL);
 
        buddy = mb_find_buddy(e4b, order, &max);
@@ -1276,7 +1260,7 @@ static int mb_mark_used(struct ext4_buddy *e4b, struct ext4_free_extent *ex)
 
        BUG_ON(start + len > (e4b->bd_sb->s_blocksize << 3));
        BUG_ON(e4b->bd_group != ex->fe_group);
-       BUG_ON(!ext4_is_group_locked(e4b->bd_sb, e4b->bd_group));
+       assert_spin_locked(ext4_group_lock_ptr(e4b->bd_sb, e4b->bd_group));
        mb_check_buddy(e4b);
        mb_mark_used_double(e4b, start, len);
 
@@ -1330,8 +1314,7 @@ static int mb_mark_used(struct ext4_buddy *e4b, struct ext4_free_extent *ex)
                e4b->bd_info->bb_counters[ord]++;
        }
 
-       mb_set_bits(sb_bgl_lock(EXT4_SB(e4b->bd_sb), ex->fe_group),
-                       EXT4_MB_BITMAP(e4b), ex->fe_start, len0);
+       mb_set_bits(EXT4_MB_BITMAP(e4b), ex->fe_start, len0);
        mb_check_buddy(e4b);
 
        return ret;
@@ -1726,7 +1709,6 @@ 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);
 
        BUG_ON(cr < 0 || cr >= 4);
@@ -1742,10 +1724,6 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac,
        switch (cr) {
        case 0:
                BUG_ON(ac->ac_2order == 0);
-               /* If this group is uninitialized, skip it initially */
-               desc = ext4_get_group_desc(ac->ac_sb, group, NULL);
-               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) &&
@@ -1788,6 +1766,7 @@ int ext4_mb_get_buddy_cache_lock(struct super_block *sb, ext4_group_t group)
        int block, pnum;
        int blocks_per_page;
        int groups_per_page;
+       ext4_group_t ngroups = ext4_get_groups_count(sb);
        ext4_group_t first_group;
        struct ext4_group_info *grp;
 
@@ -1807,7 +1786,7 @@ int ext4_mb_get_buddy_cache_lock(struct super_block *sb, ext4_group_t group)
        /* read all groups the page covers into the cache */
        for (i = 0; i < groups_per_page; i++) {
 
-               if ((first_group + i) >= EXT4_SB(sb)->s_groups_count)
+               if ((first_group + i) >= ngroups)
                        break;
                grp = ext4_get_group_info(sb, first_group + i);
                /* take all groups write allocation
@@ -1945,8 +1924,7 @@ err:
 static noinline_for_stack int
 ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
 {
-       ext4_group_t group;
-       ext4_group_t i;
+       ext4_group_t ngroups, group, i;
        int cr;
        int err = 0;
        int bsbits;
@@ -1957,6 +1935,7 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
 
        sb = ac->ac_sb;
        sbi = EXT4_SB(sb);
+       ngroups = ext4_get_groups_count(sb);
        BUG_ON(ac->ac_status == AC_STATUS_FOUND);
 
        /* first, try the goal */
@@ -2017,11 +1996,11 @@ repeat:
                 */
                group = ac->ac_g_ex.fe_group;
 
-               for (i = 0; i < EXT4_SB(sb)->s_groups_count; group++, i++) {
+               for (i = 0; i < ngroups; group++, i++) {
                        struct ext4_group_info *grp;
                        struct ext4_group_desc *desc;
 
-                       if (group == EXT4_SB(sb)->s_groups_count)
+                       if (group == ngroups)
                                group = 0;
 
                        /* quick check to skip empty groups */
@@ -2064,9 +2043,7 @@ repeat:
 
                        ac->ac_groups_scanned++;
                        desc = ext4_get_group_desc(sb, group, NULL);
-                       if (cr == 0 || (desc->bg_flags &
-                                       cpu_to_le16(EXT4_BG_BLOCK_UNINIT) &&
-                                       ac->ac_2order != 0))
+                       if (cr == 0)
                                ext4_mb_simple_scan_group(ac, &e4b);
                        else if (cr == 1 &&
                                        ac->ac_g_ex.fe_len == sbi->s_stripe)
@@ -2315,12 +2292,10 @@ static struct file_operations ext4_mb_seq_history_fops = {
 static void *ext4_mb_seq_groups_start(struct seq_file *seq, loff_t *pos)
 {
        struct super_block *sb = seq->private;
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
        ext4_group_t group;
 
-       if (*pos < 0 || *pos >= sbi->s_groups_count)
+       if (*pos < 0 || *pos >= ext4_get_groups_count(sb))
                return NULL;
-
        group = *pos + 1;
        return (void *) ((unsigned long) group);
 }
@@ -2328,11 +2303,10 @@ static void *ext4_mb_seq_groups_start(struct seq_file *seq, loff_t *pos)
 static void *ext4_mb_seq_groups_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        struct super_block *sb = seq->private;
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
        ext4_group_t group;
 
        ++*pos;
-       if (*pos < 0 || *pos >= sbi->s_groups_count)
+       if (*pos < 0 || *pos >= ext4_get_groups_count(sb))
                return NULL;
        group = *pos + 1;
        return (void *) ((unsigned long) group);
@@ -2420,7 +2394,8 @@ static void ext4_mb_history_release(struct super_block *sb)
 
        if (sbi->s_proc != NULL) {
                remove_proc_entry("mb_groups", sbi->s_proc);
-               remove_proc_entry("mb_history", sbi->s_proc);
+               if (sbi->s_mb_history_max)
+                       remove_proc_entry("mb_history", sbi->s_proc);
        }
        kfree(sbi->s_mb_history);
 }
@@ -2431,17 +2406,17 @@ static void ext4_mb_history_init(struct super_block *sb)
        int i;
 
        if (sbi->s_proc != NULL) {
-               proc_create_data("mb_history", S_IRUGO, sbi->s_proc,
-                                &ext4_mb_seq_history_fops, sb);
+               if (sbi->s_mb_history_max)
+                       proc_create_data("mb_history", S_IRUGO, sbi->s_proc,
+                                        &ext4_mb_seq_history_fops, sb);
                proc_create_data("mb_groups", S_IRUGO, sbi->s_proc,
                                 &ext4_mb_seq_groups_fops, sb);
        }
 
-       sbi->s_mb_history_max = 1000;
        sbi->s_mb_history_cur = 0;
        spin_lock_init(&sbi->s_mb_history_lock);
        i = sbi->s_mb_history_max * sizeof(struct ext4_mb_history);
-       sbi->s_mb_history = kzalloc(i, GFP_KERNEL);
+       sbi->s_mb_history = i ? kzalloc(i, GFP_KERNEL) : NULL;
        /* if we can't allocate history, then we simple won't use it */
 }
 
@@ -2451,7 +2426,7 @@ ext4_mb_store_history(struct ext4_allocation_context *ac)
        struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb);
        struct ext4_mb_history h;
 
-       if (unlikely(sbi->s_mb_history == NULL))
+       if (sbi->s_mb_history == NULL)
                return;
 
        if (!(ac->ac_op & sbi->s_mb_history_filter))
@@ -2587,6 +2562,7 @@ void ext4_mb_update_group_info(struct ext4_group_info *grp, ext4_grpblk_t add)
 
 static int ext4_mb_init_backend(struct super_block *sb)
 {
+       ext4_group_t ngroups = ext4_get_groups_count(sb);
        ext4_group_t i;
        int metalen;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -2598,7 +2574,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
        struct ext4_group_desc *desc;
 
        /* This is the number of blocks used by GDT */
-       num_meta_group_infos = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) -
+       num_meta_group_infos = (ngroups + EXT4_DESC_PER_BLOCK(sb) -
                                1) >> EXT4_DESC_PER_BLOCK_BITS(sb);
 
        /*
@@ -2644,7 +2620,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
        for (i = 0; i < num_meta_group_infos; i++) {
                if ((i + 1) == num_meta_group_infos)
                        metalen = sizeof(*meta_group_info) *
-                               (sbi->s_groups_count -
+                               (ngroups -
                                        (i << EXT4_DESC_PER_BLOCK_BITS(sb)));
                meta_group_info = kmalloc(metalen, GFP_KERNEL);
                if (meta_group_info == NULL) {
@@ -2655,7 +2631,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
                sbi->s_group_info[i] = meta_group_info;
        }
 
-       for (i = 0; i < sbi->s_groups_count; i++) {
+       for (i = 0; i < ngroups; i++) {
                desc = ext4_get_group_desc(sb, i, NULL);
                if (desc == NULL) {
                        printk(KERN_ERR
@@ -2761,7 +2737,7 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        return 0;
 }
 
-/* need to called with ext4 group lock (ext4_lock_group) */
+/* need to called with the ext4 group lock held */
 static void ext4_mb_cleanup_pa(struct ext4_group_info *grp)
 {
        struct ext4_prealloc_space *pa;
@@ -2781,13 +2757,14 @@ static void ext4_mb_cleanup_pa(struct ext4_group_info *grp)
 
 int ext4_mb_release(struct super_block *sb)
 {
+       ext4_group_t ngroups = ext4_get_groups_count(sb);
        ext4_group_t i;
        int num_meta_group_infos;
        struct ext4_group_info *grinfo;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
        if (sbi->s_group_info) {
-               for (i = 0; i < sbi->s_groups_count; i++) {
+               for (i = 0; i < ngroups; i++) {
                        grinfo = ext4_get_group_info(sb, i);
 #ifdef DOUBLE_CHECK
                        kfree(grinfo->bb_bitmap);
@@ -2797,7 +2774,7 @@ int ext4_mb_release(struct super_block *sb)
                        ext4_unlock_group(sb, i);
                        kfree(grinfo);
                }
-               num_meta_group_infos = (sbi->s_groups_count +
+               num_meta_group_infos = (ngroups +
                                EXT4_DESC_PER_BLOCK(sb) - 1) >>
                        EXT4_DESC_PER_BLOCK_BITS(sb);
                for (i = 0; i < num_meta_group_infos; i++)
@@ -2984,27 +2961,25 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
                + le32_to_cpu(es->s_first_data_block);
 
        len = ac->ac_b_ex.fe_len;
-       if (in_range(ext4_block_bitmap(sb, gdp), block, len) ||
-           in_range(ext4_inode_bitmap(sb, gdp), block, len) ||
-           in_range(block, ext4_inode_table(sb, gdp),
-                    EXT4_SB(sb)->s_itb_per_group) ||
-           in_range(block + len - 1, ext4_inode_table(sb, gdp),
-                    EXT4_SB(sb)->s_itb_per_group)) {
+       if (!ext4_data_block_valid(sbi, block, len)) {
                ext4_error(sb, __func__,
-                          "Allocating block %llu in system zone of %d group\n",
-                          block, ac->ac_b_ex.fe_group);
+                          "Allocating blocks %llu-%llu which overlap "
+                          "fs metadata\n", block, block+len);
                /* File system mounted not to panic on error
                 * Fix the bitmap and repeat the block allocation
                 * We leak some of the blocks here.
                 */
-               mb_set_bits(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group),
-                               bitmap_bh->b_data, ac->ac_b_ex.fe_start,
-                               ac->ac_b_ex.fe_len);
+               ext4_lock_group(sb, ac->ac_b_ex.fe_group);
+               mb_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start,
+                           ac->ac_b_ex.fe_len);
+               ext4_unlock_group(sb, ac->ac_b_ex.fe_group);
                err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
                if (!err)
                        err = -EAGAIN;
                goto out_err;
        }
+
+       ext4_lock_group(sb, ac->ac_b_ex.fe_group);
 #ifdef AGGRESSIVE_CHECK
        {
                int i;
@@ -3014,9 +2989,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
                }
        }
 #endif
-       spin_lock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
-       mb_set_bits(NULL, bitmap_bh->b_data,
-                               ac->ac_b_ex.fe_start, ac->ac_b_ex.fe_len);
+       mb_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start,ac->ac_b_ex.fe_len);
        if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
                gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
                ext4_free_blks_set(sb, gdp,
@@ -3026,7 +2999,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
        len = ext4_free_blks_count(sb, gdp) - ac->ac_b_ex.fe_len;
        ext4_free_blks_set(sb, gdp, len);
        gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp);
-       spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
+
+       ext4_unlock_group(sb, ac->ac_b_ex.fe_group);
        percpu_counter_sub(&sbi->s_freeblocks_counter, ac->ac_b_ex.fe_len);
        /*
         * Now reduce the dirty block count also. Should not go negative
@@ -3459,7 +3433,7 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
  * the function goes through all block freed in the group
  * but not yet committed and marks them used in in-core bitmap.
  * buddy must be generated from this bitmap
- * Need to be called with ext4 group lock (ext4_lock_group)
+ * Need to be called with the ext4 group lock held
  */
 static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
                                                ext4_group_t group)
@@ -3473,9 +3447,7 @@ static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
 
        while (n) {
                entry = rb_entry(n, struct ext4_free_data, node);
-               mb_set_bits(sb_bgl_lock(EXT4_SB(sb), group),
-                               bitmap, entry->start_blk,
-                               entry->count);
+               mb_set_bits(bitmap, entry->start_blk, entry->count);
                n = rb_next(n);
        }
        return;
@@ -3484,7 +3456,7 @@ static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
 /*
  * the function goes through all preallocation in this group and marks them
  * used in in-core bitmap. buddy must be generated from this bitmap
- * Need to be called with ext4 group lock (ext4_lock_group)
+ * Need to be called with ext4 group lock held
  */
 static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
                                        ext4_group_t group)
@@ -3516,8 +3488,7 @@ static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
                if (unlikely(len == 0))
                        continue;
                BUG_ON(groupnr != group);
-               mb_set_bits(sb_bgl_lock(EXT4_SB(sb), group),
-                                               bitmap, start, len);
+               mb_set_bits(bitmap, start, len);
                preallocated += len;
                count++;
        }
@@ -4121,7 +4092,7 @@ static void ext4_mb_return_to_preallocation(struct inode *inode,
 static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
 {
        struct super_block *sb = ac->ac_sb;
-       ext4_group_t i;
+       ext4_group_t ngroups, i;
 
        printk(KERN_ERR "EXT4-fs: Can't allocate:"
                        " Allocation context details:\n");
@@ -4145,7 +4116,8 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
        printk(KERN_ERR "EXT4-fs: %lu scanned, %d found\n", ac->ac_ex_scanned,
                ac->ac_found);
        printk(KERN_ERR "EXT4-fs: groups: \n");
-       for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
+       ngroups = ext4_get_groups_count(sb);
+       for (i = 0; i < ngroups; i++) {
                struct ext4_group_info *grp = ext4_get_group_info(sb, i);
                struct ext4_prealloc_space *pa;
                ext4_grpblk_t start;
@@ -4469,13 +4441,13 @@ static int ext4_mb_release_context(struct ext4_allocation_context *ac)
 
 static int ext4_mb_discard_preallocations(struct super_block *sb, int needed)
 {
-       ext4_group_t i;
+       ext4_group_t i, ngroups = ext4_get_groups_count(sb);
        int ret;
        int freed = 0;
 
        trace_mark(ext4_mb_discard_preallocations, "dev %s needed %d",
                   sb->s_id, needed);
-       for (i = 0; i < EXT4_SB(sb)->s_groups_count && needed > 0; i++) {
+       for (i = 0; i < ngroups && needed > 0; i++) {
                ret = ext4_mb_discard_group_preallocations(sb, i, needed);
                freed += ret;
                needed -= ret;
@@ -4859,29 +4831,25 @@ do_more:
                new_entry->group  = block_group;
                new_entry->count = count;
                new_entry->t_tid = handle->h_transaction->t_tid;
+
                ext4_lock_group(sb, block_group);
-               mb_clear_bits(sb_bgl_lock(sbi, block_group), bitmap_bh->b_data,
-                               bit, count);
+               mb_clear_bits(bitmap_bh->b_data, bit, count);
                ext4_mb_free_metadata(handle, &e4b, new_entry);
-               ext4_unlock_group(sb, block_group);
        } else {
-               ext4_lock_group(sb, block_group);
                /* need to update group_info->bb_free and bitmap
                 * with group lock held. generate_buddy look at
                 * them with group lock_held
                 */
-               mb_clear_bits(sb_bgl_lock(sbi, block_group), bitmap_bh->b_data,
-                               bit, count);
+               ext4_lock_group(sb, block_group);
+               mb_clear_bits(bitmap_bh->b_data, bit, count);
                mb_free_blocks(inode, &e4b, bit, count);
                ext4_mb_return_to_preallocation(inode, &e4b, block, count);
-               ext4_unlock_group(sb, block_group);
        }
 
-       spin_lock(sb_bgl_lock(sbi, block_group));
        ret = ext4_free_blks_count(sb, gdp) + count;
        ext4_free_blks_set(sb, gdp, ret);
        gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp);
-       spin_unlock(sb_bgl_lock(sbi, block_group));
+       ext4_unlock_group(sb, block_group);
        percpu_counter_add(&sbi->s_freeblocks_counter, count);
 
        if (sbi->s_log_groups_per_flex) {
index dd9e6cd5f6cf4dc97ae6c97b4c6c5c9d5bee9e4d..75e34f69215bfb3c24a6ecf9545eace9a36053f7 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/mutex.h>
 #include "ext4_jbd2.h"
 #include "ext4.h"
-#include "group.h"
 
 /*
  * with AGGRESSIVE_CHECK allocator runs consistency checks over
index 22098e1cd085911a7aeffc975ac7a0773a32bbc0..07eb6649e4fa1396d80e03186ffd76559b4c6709 100644 (file)
@@ -37,7 +37,6 @@
 #include "ext4.h"
 #include "ext4_jbd2.h"
 
-#include "namei.h"
 #include "xattr.h"
 #include "acl.h"
 
@@ -750,7 +749,7 @@ static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize,
                        ext4fs_dirhash(de->name, de->name_len, &h);
                        map_tail--;
                        map_tail->hash = h.hash;
-                       map_tail->offs = (u16) ((char *) de - base);
+                       map_tail->offs = ((char *) de - base)>>2;
                        map_tail->size = le16_to_cpu(de->rec_len);
                        count++;
                        cond_resched();
@@ -1148,7 +1147,8 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count,
        unsigned rec_len = 0;
 
        while (count--) {
-               struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *) (from + map->offs);
+               struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *) 
+                                               (from + (map->offs<<2));
                rec_len = EXT4_DIR_REC_LEN(de->name_len);
                memcpy (to, de, rec_len);
                ((struct ext4_dir_entry_2 *) to)->rec_len =
@@ -1997,7 +1997,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
        if (!ext4_handle_valid(handle))
                return 0;
 
-       lock_super(sb);
+       mutex_lock(&EXT4_SB(sb)->s_orphan_lock);
        if (!list_empty(&EXT4_I(inode)->i_orphan))
                goto out_unlock;
 
@@ -2006,9 +2006,13 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
 
        /* @@@ FIXME: Observation from aviro:
         * I think I can trigger J_ASSERT in ext4_orphan_add().  We block
-        * here (on lock_super()), so race with ext4_link() which might bump
+        * here (on s_orphan_lock), so race with ext4_link() which might bump
         * ->i_nlink. For, say it, character device. Not a regular file,
         * not a directory, not a symlink and ->i_nlink > 0.
+        *
+        * tytso, 4/25/2009: I'm not sure how that could happen;
+        * shouldn't the fs core protect us from these sort of
+        * unlink()/link() races?
         */
        J_ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
                  S_ISLNK(inode->i_mode)) || inode->i_nlink == 0);
@@ -2045,7 +2049,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
        jbd_debug(4, "orphan inode %lu will point to %d\n",
                        inode->i_ino, NEXT_ORPHAN(inode));
 out_unlock:
-       unlock_super(sb);
+       mutex_unlock(&EXT4_SB(sb)->s_orphan_lock);
        ext4_std_error(inode->i_sb, err);
        return err;
 }
@@ -2066,11 +2070,9 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
        if (!ext4_handle_valid(handle))
                return 0;
 
-       lock_super(inode->i_sb);
-       if (list_empty(&ei->i_orphan)) {
-               unlock_super(inode->i_sb);
-               return 0;
-       }
+       mutex_lock(&EXT4_SB(inode->i_sb)->s_orphan_lock);
+       if (list_empty(&ei->i_orphan))
+               goto out;
 
        ino_next = NEXT_ORPHAN(inode);
        prev = ei->i_orphan.prev;
@@ -2120,7 +2122,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
 out_err:
        ext4_std_error(inode->i_sb, err);
 out:
-       unlock_super(inode->i_sb);
+       mutex_unlock(&EXT4_SB(inode->i_sb)->s_orphan_lock);
        return err;
 
 out_brelse:
@@ -2533,6 +2535,7 @@ const struct inode_operations ext4_dir_inode_operations = {
        .removexattr    = generic_removexattr,
 #endif
        .permission     = ext4_permission,
+       .fiemap         = ext4_fiemap,
 };
 
 const struct inode_operations ext4_special_inode_operations = {
diff --git a/fs/ext4/namei.h b/fs/ext4/namei.h
deleted file mode 100644 (file)
index 5e4dfff..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*  linux/fs/ext4/namei.h
- *
- * Copyright (C) 2005 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
-*/
-
-extern struct dentry *ext4_get_parent(struct dentry *child);
index 546c7dd869e19176e77cb54278e9bdfc2b520da4..27eb289eea3708fb4ee71dc26e31def645c5a03f 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/slab.h>
 
 #include "ext4_jbd2.h"
-#include "group.h"
 
 #define outside(b, first, last)        ((b) < (first) || (b) >= (last))
 #define inside(b, first, last) ((b) >= (first) && (b) < (last))
@@ -193,7 +192,7 @@ static int setup_new_group_blocks(struct super_block *sb,
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
-       lock_super(sb);
+       mutex_lock(&sbi->s_resize_lock);
        if (input->group != sbi->s_groups_count) {
                err = -EBUSY;
                goto exit_journal;
@@ -302,7 +301,7 @@ exit_bh:
        brelse(bh);
 
 exit_journal:
-       unlock_super(sb);
+       mutex_unlock(&sbi->s_resize_lock);
        if ((err2 = ext4_journal_stop(handle)) && !err)
                err = err2;
 
@@ -643,11 +642,12 @@ exit_free:
  * important part is that the new block and inode counts are in the backup
  * superblocks, and the location of the new group metadata in the GDT backups.
  *
- * We do not need lock_super() for this, because these blocks are not
- * otherwise touched by the filesystem code when it is mounted.  We don't
- * need to worry about last changing from sbi->s_groups_count, because the
- * worst that can happen is that we do not copy the full number of backups
- * at this time.  The resize which changed s_groups_count will backup again.
+ * We do not need take the s_resize_lock for this, because these
+ * blocks are not otherwise touched by the filesystem code when it is
+ * mounted.  We don't need to worry about last changing from
+ * sbi->s_groups_count, because the worst that can happen is that we
+ * do not copy the full number of backups at this time.  The resize
+ * which changed s_groups_count will backup again.
  */
 static void update_backups(struct super_block *sb,
                           int blk_off, char *data, int size)
@@ -809,7 +809,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
                goto exit_put;
        }
 
-       lock_super(sb);
+       mutex_lock(&sbi->s_resize_lock);
        if (input->group != sbi->s_groups_count) {
                ext4_warning(sb, __func__,
                             "multiple resizers run on filesystem!");
@@ -840,7 +840,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
         /*
          * OK, now we've set up the new group.  Time to make it active.
          *
-         * Current kernels don't lock all allocations via lock_super(),
+         * We do not lock all allocations via s_resize_lock
          * so we have to be safe wrt. concurrent accesses the group
          * data.  So we need to be careful to set all of the relevant
          * group descriptor data etc. *before* we enable the group.
@@ -900,12 +900,12 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
         *
         * The precise rules we use are:
         *
-        * * Writers of s_groups_count *must* hold lock_super
+        * * Writers of s_groups_count *must* hold s_resize_lock
         * AND
         * * Writers must perform a smp_wmb() after updating all dependent
         *   data and before modifying the groups count
         *
-        * * Readers must hold lock_super() over the access
+        * * Readers must hold s_resize_lock over the access
         * OR
         * * Readers must perform an smp_rmb() after reading the groups count
         *   and before reading any dependent data.
@@ -948,7 +948,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
        sb->s_dirt = 1;
 
 exit_journal:
-       unlock_super(sb);
+       mutex_unlock(&sbi->s_resize_lock);
        if ((err2 = ext4_journal_stop(handle)) && !err)
                err = err2;
        if (!err) {
@@ -986,7 +986,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
 
        /* We don't need to worry about locking wrt other resizers just
         * yet: we're going to revalidate es->s_blocks_count after
-        * taking lock_super() below. */
+        * taking the s_resize_lock below. */
        o_blocks_count = ext4_blocks_count(es);
        o_groups_count = EXT4_SB(sb)->s_groups_count;
 
@@ -1056,11 +1056,11 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
                goto exit_put;
        }
 
-       lock_super(sb);
+       mutex_lock(&EXT4_SB(sb)->s_resize_lock);
        if (o_blocks_count != ext4_blocks_count(es)) {
                ext4_warning(sb, __func__,
                             "multiple resizers run on filesystem!");
-               unlock_super(sb);
+               mutex_unlock(&EXT4_SB(sb)->s_resize_lock);
                ext4_journal_stop(handle);
                err = -EBUSY;
                goto exit_put;
@@ -1070,14 +1070,14 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
                                                 EXT4_SB(sb)->s_sbh))) {
                ext4_warning(sb, __func__,
                             "error %d on journal write access", err);
-               unlock_super(sb);
+               mutex_unlock(&EXT4_SB(sb)->s_resize_lock);
                ext4_journal_stop(handle);
                goto exit_put;
        }
        ext4_blocks_count_set(es, o_blocks_count + add);
        ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
        sb->s_dirt = 1;
-       unlock_super(sb);
+       mutex_unlock(&EXT4_SB(sb)->s_resize_lock);
        ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count,
                   o_blocks_count + add);
        /* We add the blocks to the bitmap and set the group need init bit */
index 2958f4e6f222a8956f595145b1fe31e16e4eec9d..f016707597a728c37e6ea0a5150f6b16ac2ae577 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/string.h>
 #include <linux/fs.h>
 #include <linux/time.h>
+#include <linux/vmalloc.h>
 #include <linux/jbd2.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include "ext4_jbd2.h"
 #include "xattr.h"
 #include "acl.h"
-#include "namei.h"
-#include "group.h"
+
+static int default_mb_history_length = 1000;
+
+module_param_named(default_mb_history_length, default_mb_history_length,
+                  int, 0644);
+MODULE_PARM_DESC(default_mb_history_length,
+                "Default number of entries saved for mb_history");
 
 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);
-static int ext4_commit_super(struct super_block *sb,
-                             struct ext4_super_block *es, int sync);
+static int ext4_commit_super(struct super_block *sb, int sync);
 static void ext4_mark_recovery_complete(struct super_block *sb,
                                        struct ext4_super_block *es);
 static void ext4_clear_journal_err(struct super_block *sb,
@@ -74,7 +79,7 @@ ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
 {
        return le32_to_cpu(bg->bg_block_bitmap_lo) |
                (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
-               (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0);
+                (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0);
 }
 
 ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
@@ -82,7 +87,7 @@ ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
 {
        return le32_to_cpu(bg->bg_inode_bitmap_lo) |
                (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
-               (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0);
+                (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0);
 }
 
 ext4_fsblk_t ext4_inode_table(struct super_block *sb,
@@ -90,7 +95,7 @@ ext4_fsblk_t ext4_inode_table(struct super_block *sb,
 {
        return le32_to_cpu(bg->bg_inode_table_lo) |
                (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
-               (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0);
+                (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0);
 }
 
 __u32 ext4_free_blks_count(struct super_block *sb,
@@ -98,7 +103,7 @@ __u32 ext4_free_blks_count(struct super_block *sb,
 {
        return le16_to_cpu(bg->bg_free_blocks_count_lo) |
                (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
-               (__u32)le16_to_cpu(bg->bg_free_blocks_count_hi) << 16 : 0);
+                (__u32)le16_to_cpu(bg->bg_free_blocks_count_hi) << 16 : 0);
 }
 
 __u32 ext4_free_inodes_count(struct super_block *sb,
@@ -106,7 +111,7 @@ __u32 ext4_free_inodes_count(struct super_block *sb,
 {
        return le16_to_cpu(bg->bg_free_inodes_count_lo) |
                (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
-               (__u32)le16_to_cpu(bg->bg_free_inodes_count_hi) << 16 : 0);
+                (__u32)le16_to_cpu(bg->bg_free_inodes_count_hi) << 16 : 0);
 }
 
 __u32 ext4_used_dirs_count(struct super_block *sb,
@@ -114,7 +119,7 @@ __u32 ext4_used_dirs_count(struct super_block *sb,
 {
        return le16_to_cpu(bg->bg_used_dirs_count_lo) |
                (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
-               (__u32)le16_to_cpu(bg->bg_used_dirs_count_hi) << 16 : 0);
+                (__u32)le16_to_cpu(bg->bg_used_dirs_count_hi) << 16 : 0);
 }
 
 __u32 ext4_itable_unused_count(struct super_block *sb,
@@ -122,7 +127,7 @@ __u32 ext4_itable_unused_count(struct super_block *sb,
 {
        return le16_to_cpu(bg->bg_itable_unused_lo) |
                (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
-               (__u32)le16_to_cpu(bg->bg_itable_unused_hi) << 16 : 0);
+                (__u32)le16_to_cpu(bg->bg_itable_unused_hi) << 16 : 0);
 }
 
 void ext4_block_bitmap_set(struct super_block *sb,
@@ -202,8 +207,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
        journal = EXT4_SB(sb)->s_journal;
        if (journal) {
                if (is_journal_aborted(journal)) {
-                       ext4_abort(sb, __func__,
-                                  "Detected aborted journal");
+                       ext4_abort(sb, __func__, "Detected aborted journal");
                        return ERR_PTR(-EROFS);
                }
                return jbd2_journal_start(journal, nblocks);
@@ -302,10 +306,10 @@ static void ext4_handle_error(struct super_block *sb)
                        jbd2_journal_abort(journal, -EIO);
        }
        if (test_opt(sb, ERRORS_RO)) {
-               printk(KERN_CRIT "Remounting filesystem read-only\n");
+               ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
                sb->s_flags |= MS_RDONLY;
        }
-       ext4_commit_super(sb, es, 1);
+       ext4_commit_super(sb, 1);
        if (test_opt(sb, ERRORS_PANIC))
                panic("EXT4-fs (device %s): panic forced after error\n",
                        sb->s_id);
@@ -395,8 +399,6 @@ void ext4_abort(struct super_block *sb, const char *function,
 {
        va_list args;
 
-       printk(KERN_CRIT "ext4_abort called.\n");
-
        va_start(args, fmt);
        printk(KERN_CRIT "EXT4-fs error (device %s): %s: ", sb->s_id, function);
        vprintk(fmt, args);
@@ -409,7 +411,7 @@ void ext4_abort(struct super_block *sb, const char *function,
        if (sb->s_flags & MS_RDONLY)
                return;
 
-       printk(KERN_CRIT "Remounting filesystem read-only\n");
+       ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
        EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
        sb->s_flags |= MS_RDONLY;
        EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT;
@@ -417,6 +419,18 @@ void ext4_abort(struct super_block *sb, const char *function,
                jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
 }
 
+void ext4_msg (struct super_block * sb, const char *prefix,
+                  const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       printk("%sEXT4-fs (%s): ", prefix, sb->s_id);
+       vprintk(fmt, args);
+       printk("\n");
+       va_end(args);
+}
+
 void ext4_warning(struct super_block *sb, const char *function,
                  const char *fmt, ...)
 {
@@ -431,7 +445,7 @@ void ext4_warning(struct super_block *sb, const char *function,
 }
 
 void ext4_grp_locked_error(struct super_block *sb, ext4_group_t grp,
-                               const char *function, const char *fmt, ...)
+                          const char *function, const char *fmt, ...)
 __releases(bitlock)
 __acquires(bitlock)
 {
@@ -447,7 +461,7 @@ __acquires(bitlock)
        if (test_opt(sb, ERRORS_CONT)) {
                EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
                es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
-               ext4_commit_super(sb, es, 0);
+               ext4_commit_super(sb, 0);
                return;
        }
        ext4_unlock_group(sb, grp);
@@ -467,7 +481,6 @@ __acquires(bitlock)
        return;
 }
 
-
 void ext4_update_dynamic_rev(struct super_block *sb)
 {
        struct ext4_super_block *es = EXT4_SB(sb)->s_es;
@@ -496,7 +509,7 @@ void ext4_update_dynamic_rev(struct super_block *sb)
 /*
  * Open the external journal device
  */
-static struct block_device *ext4_blkdev_get(dev_t dev)
+static struct block_device *ext4_blkdev_get(dev_t dev, struct super_block *sb)
 {
        struct block_device *bdev;
        char b[BDEVNAME_SIZE];
@@ -507,7 +520,7 @@ static struct block_device *ext4_blkdev_get(dev_t dev)
        return bdev;
 
 fail:
-       printk(KERN_ERR "EXT4-fs: failed to open journal device %s: %ld\n",
+       ext4_msg(sb, KERN_ERR, "failed to open journal device %s: %ld",
                        __bdevname(dev, b), PTR_ERR(bdev));
        return NULL;
 }
@@ -543,8 +556,8 @@ static void dump_orphan_list(struct super_block *sb, struct ext4_sb_info *sbi)
 {
        struct list_head *l;
 
-       printk(KERN_ERR "sb orphan head is %d\n",
-              le32_to_cpu(sbi->s_es->s_last_orphan));
+       ext4_msg(sb, KERN_ERR, "sb orphan head is %d",
+                le32_to_cpu(sbi->s_es->s_last_orphan));
 
        printk(KERN_ERR "sb_info orphan list:\n");
        list_for_each(l, &sbi->s_orphan) {
@@ -563,6 +576,7 @@ static void ext4_put_super(struct super_block *sb)
        struct ext4_super_block *es = sbi->s_es;
        int i, err;
 
+       ext4_release_system_zone(sb);
        ext4_mb_release(sb);
        ext4_ext_release(sb);
        ext4_xattr_put_super(sb);
@@ -576,7 +590,7 @@ static void ext4_put_super(struct super_block *sb)
        if (!(sb->s_flags & MS_RDONLY)) {
                EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
                es->s_state = cpu_to_le16(sbi->s_mount_state);
-               ext4_commit_super(sb, es, 1);
+               ext4_commit_super(sb, 1);
        }
        if (sbi->s_proc) {
                remove_proc_entry(sb->s_id, ext4_proc_root);
@@ -586,7 +600,10 @@ static void ext4_put_super(struct super_block *sb)
        for (i = 0; i < sbi->s_gdb_count; i++)
                brelse(sbi->s_group_desc[i]);
        kfree(sbi->s_group_desc);
-       kfree(sbi->s_flex_groups);
+       if (is_vmalloc_addr(sbi->s_flex_groups))
+               vfree(sbi->s_flex_groups);
+       else
+               kfree(sbi->s_flex_groups);
        percpu_counter_destroy(&sbi->s_freeblocks_counter);
        percpu_counter_destroy(&sbi->s_freeinodes_counter);
        percpu_counter_destroy(&sbi->s_dirs_counter);
@@ -629,7 +646,6 @@ static void ext4_put_super(struct super_block *sb)
        lock_kernel();
        kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
-       return;
 }
 
 static struct kmem_cache *ext4_inode_cachep;
@@ -644,6 +660,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        ei = kmem_cache_alloc(ext4_inode_cachep, GFP_NOFS);
        if (!ei)
                return NULL;
+
 #ifdef CONFIG_EXT4_FS_POSIX_ACL
        ei->i_acl = EXT4_ACL_NOT_CACHED;
        ei->i_default_acl = EXT4_ACL_NOT_CACHED;
@@ -664,14 +681,16 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        ei->i_allocated_meta_blocks = 0;
        ei->i_delalloc_reserved_flag = 0;
        spin_lock_init(&(ei->i_block_reservation_lock));
+
        return &ei->vfs_inode;
 }
 
 static void ext4_destroy_inode(struct inode *inode)
 {
        if (!list_empty(&(EXT4_I(inode)->i_orphan))) {
-               printk("EXT4 Inode %p: orphan list check failed!\n",
-                       EXT4_I(inode));
+               ext4_msg(inode->i_sb, KERN_ERR,
+                        "Inode %lu (%p): orphan list check failed!",
+                        inode->i_ino, EXT4_I(inode));
                print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4,
                                EXT4_I(inode), sizeof(struct ext4_inode_info),
                                true);
@@ -870,12 +889,12 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
                seq_puts(seq, ",noauto_da_alloc");
 
        ext4_show_quota_options(seq, sb);
+
        return 0;
 }
 
-
 static struct inode *ext4_nfs_get_inode(struct super_block *sb,
-               u64 ino, u32 generation)
+                                       u64 ino, u32 generation)
 {
        struct inode *inode;
 
@@ -904,14 +923,14 @@ static struct inode *ext4_nfs_get_inode(struct super_block *sb,
 }
 
 static struct dentry *ext4_fh_to_dentry(struct super_block *sb, struct fid *fid,
-               int fh_len, int fh_type)
+                                       int fh_len, int fh_type)
 {
        return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
                                    ext4_nfs_get_inode);
 }
 
 static struct dentry *ext4_fh_to_parent(struct super_block *sb, struct fid *fid,
-               int fh_len, int fh_type)
+                                       int fh_len, int fh_type)
 {
        return generic_fh_to_parent(sb, fid, fh_len, fh_type,
                                    ext4_nfs_get_inode);
@@ -923,7 +942,8 @@ static struct dentry *ext4_fh_to_parent(struct super_block *sb, struct fid *fid,
  * which would prevent try_to_free_buffers() from freeing them, we must use
  * jbd2 layer's try_to_free_buffers() function to release them.
  */
-static int bdev_try_to_free_page(struct super_block *sb, struct page *page, gfp_t wait)
+static int bdev_try_to_free_page(struct super_block *sb, struct page *page,
+                                gfp_t wait)
 {
        journal_t *journal = EXT4_SB(sb)->s_journal;
 
@@ -992,7 +1012,6 @@ static const struct super_operations ext4_sops = {
        .dirty_inode    = ext4_dirty_inode,
        .delete_inode   = ext4_delete_inode,
        .put_super      = ext4_put_super,
-       .write_super    = ext4_write_super,
        .sync_fs        = ext4_sync_fs,
        .freeze_fs      = ext4_freeze,
        .unfreeze_fs    = ext4_unfreeze,
@@ -1007,6 +1026,25 @@ static const struct super_operations ext4_sops = {
        .bdev_try_to_free_page = bdev_try_to_free_page,
 };
 
+static const struct super_operations ext4_nojournal_sops = {
+       .alloc_inode    = ext4_alloc_inode,
+       .destroy_inode  = ext4_destroy_inode,
+       .write_inode    = ext4_write_inode,
+       .dirty_inode    = ext4_dirty_inode,
+       .delete_inode   = ext4_delete_inode,
+       .write_super    = ext4_write_super,
+       .put_super      = ext4_put_super,
+       .statfs         = ext4_statfs,
+       .remount_fs     = ext4_remount,
+       .clear_inode    = ext4_clear_inode,
+       .show_options   = ext4_show_options,
+#ifdef CONFIG_QUOTA
+       .quota_read     = ext4_quota_read,
+       .quota_write    = ext4_quota_write,
+#endif
+       .bdev_try_to_free_page = bdev_try_to_free_page,
+};
+
 static const struct export_operations ext4_export_ops = {
        .fh_to_dentry = ext4_fh_to_dentry,
        .fh_to_parent = ext4_fh_to_parent,
@@ -1023,12 +1061,13 @@ enum {
        Opt_journal_update, Opt_journal_dev,
        Opt_journal_checksum, Opt_journal_async_commit,
        Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
-       Opt_data_err_abort, Opt_data_err_ignore,
+       Opt_data_err_abort, Opt_data_err_ignore, Opt_mb_history_length,
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
        Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err, Opt_resize,
        Opt_usrquota, Opt_grpquota, Opt_i_version,
        Opt_stripe, Opt_delalloc, Opt_nodelalloc,
+       Opt_block_validity, Opt_noblock_validity,
        Opt_inode_readahead_blks, Opt_journal_ioprio
 };
 
@@ -1069,6 +1108,7 @@ static const match_table_t tokens = {
        {Opt_data_writeback, "data=writeback"},
        {Opt_data_err_abort, "data_err=abort"},
        {Opt_data_err_ignore, "data_err=ignore"},
+       {Opt_mb_history_length, "mb_history_length=%u"},
        {Opt_offusrjquota, "usrjquota="},
        {Opt_usrjquota, "usrjquota=%s"},
        {Opt_offgrpjquota, "grpjquota="},
@@ -1087,6 +1127,8 @@ static const match_table_t tokens = {
        {Opt_resize, "resize"},
        {Opt_delalloc, "delalloc"},
        {Opt_nodelalloc, "nodelalloc"},
+       {Opt_block_validity, "block_validity"},
+       {Opt_noblock_validity, "noblock_validity"},
        {Opt_inode_readahead_blks, "inode_readahead_blks=%u"},
        {Opt_journal_ioprio, "journal_ioprio=%u"},
        {Opt_auto_da_alloc, "auto_da_alloc=%u"},
@@ -1102,8 +1144,9 @@ static ext4_fsblk_t get_sb_block(void **data)
 
        if (!options || strncmp(options, "sb=", 3) != 0)
                return 1;       /* Default location */
+
        options += 3;
-       /*todo: use simple_strtoll with >32bit ext4 */
+       /* TODO: use simple_strtoll with >32bit ext4 */
        sb_block = simple_strtoul(options, &options, 0);
        if (*options && *options != ',') {
                printk(KERN_ERR "EXT4-fs: Invalid sb specification: %s\n",
@@ -1113,6 +1156,7 @@ static ext4_fsblk_t get_sb_block(void **data)
        if (*options == ',')
                options++;
        *data = (void *) options;
+
        return sb_block;
 }
 
@@ -1206,8 +1250,7 @@ static int parse_options(char *options, struct super_block *sb,
 #else
                case Opt_user_xattr:
                case Opt_nouser_xattr:
-                       printk(KERN_ERR "EXT4 (no)user_xattr options "
-                              "not supported\n");
+                       ext4_msg(sb, KERN_ERR, "(no)user_xattr options not supported");
                        break;
 #endif
 #ifdef CONFIG_EXT4_FS_POSIX_ACL
@@ -1220,8 +1263,7 @@ static int parse_options(char *options, struct super_block *sb,
 #else
                case Opt_acl:
                case Opt_noacl:
-                       printk(KERN_ERR "EXT4 (no)acl options "
-                              "not supported\n");
+                       ext4_msg(sb, KERN_ERR, "(no)acl options not supported");
                        break;
 #endif
                case Opt_journal_update:
@@ -1231,16 +1273,16 @@ static int parse_options(char *options, struct super_block *sb,
                           user to specify an existing inode to be the
                           journal file. */
                        if (is_remount) {
-                               printk(KERN_ERR "EXT4-fs: cannot specify "
-                                      "journal on remount\n");
+                               ext4_msg(sb, KERN_ERR,
+                                        "Cannot specify journal on remount");
                                return 0;
                        }
                        set_opt(sbi->s_mount_opt, UPDATE_JOURNAL);
                        break;
                case Opt_journal_dev:
                        if (is_remount) {
-                               printk(KERN_ERR "EXT4-fs: cannot specify "
-                                      "journal on remount\n");
+                               ext4_msg(sb, KERN_ERR,
+                                       "Cannot specify journal on remount");
                                return 0;
                        }
                        if (match_int(&args[0], &option))
@@ -1294,9 +1336,8 @@ static int parse_options(char *options, struct super_block *sb,
                        if (is_remount) {
                                if ((sbi->s_mount_opt & EXT4_MOUNT_DATA_FLAGS)
                                                != data_opt) {
-                                       printk(KERN_ERR
-                                               "EXT4-fs: cannot change data "
-                                               "mode on remount\n");
+                                       ext4_msg(sb, KERN_ERR,
+                                               "Cannot change data mode on remount");
                                        return 0;
                                }
                        } else {
@@ -1310,6 +1351,13 @@ static int parse_options(char *options, struct super_block *sb,
                case Opt_data_err_ignore:
                        clear_opt(sbi->s_mount_opt, DATA_ERR_ABORT);
                        break;
+               case Opt_mb_history_length:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       if (option < 0)
+                               return 0;
+                       sbi->s_mb_history_max = option;
+                       break;
 #ifdef CONFIG_QUOTA
                case Opt_usrjquota:
                        qtype = USRQUOTA;
@@ -1319,31 +1367,31 @@ static int parse_options(char *options, struct super_block *sb,
 set_qf_name:
                        if (sb_any_quota_loaded(sb) &&
                            !sbi->s_qf_names[qtype]) {
-                               printk(KERN_ERR
-                                      "EXT4-fs: Cannot change journaled "
-                                      "quota options when quota turned on.\n");
+                               ext4_msg(sb, KERN_ERR,
+                                      "Cannot change journaled "
+                                      "quota options when quota turned on");
                                return 0;
                        }
                        qname = match_strdup(&args[0]);
                        if (!qname) {
-                               printk(KERN_ERR
-                                       "EXT4-fs: not enough memory for "
-                                       "storing quotafile name.\n");
+                               ext4_msg(sb, KERN_ERR,
+                                       "Not enough memory for "
+                                       "storing quotafile name");
                                return 0;
                        }
                        if (sbi->s_qf_names[qtype] &&
                            strcmp(sbi->s_qf_names[qtype], qname)) {
-                               printk(KERN_ERR
-                                       "EXT4-fs: %s quota file already "
-                                       "specified.\n", QTYPE2NAME(qtype));
+                               ext4_msg(sb, KERN_ERR,
+                                       "%s quota file already "
+                                       "specified", QTYPE2NAME(qtype));
                                kfree(qname);
                                return 0;
                        }
                        sbi->s_qf_names[qtype] = qname;
                        if (strchr(sbi->s_qf_names[qtype], '/')) {
-                               printk(KERN_ERR
-                                       "EXT4-fs: quotafile must be on "
-                                       "filesystem root.\n");
+                               ext4_msg(sb, KERN_ERR,
+                                       "quotafile must be on "
+                                       "filesystem root");
                                kfree(sbi->s_qf_names[qtype]);
                                sbi->s_qf_names[qtype] = NULL;
                                return 0;
@@ -1358,9 +1406,9 @@ set_qf_name:
 clear_qf_name:
                        if (sb_any_quota_loaded(sb) &&
                            sbi->s_qf_names[qtype]) {
-                               printk(KERN_ERR "EXT4-fs: Cannot change "
+                               ext4_msg(sb, KERN_ERR, "Cannot change "
                                        "journaled quota options when "
-                                       "quota turned on.\n");
+                                       "quota turned on");
                                return 0;
                        }
                        /*
@@ -1377,9 +1425,9 @@ clear_qf_name:
 set_qf_format:
                        if (sb_any_quota_loaded(sb) &&
                            sbi->s_jquota_fmt != qfmt) {
-                               printk(KERN_ERR "EXT4-fs: Cannot change "
+                               ext4_msg(sb, KERN_ERR, "Cannot change "
                                        "journaled quota options when "
-                                       "quota turned on.\n");
+                                       "quota turned on");
                                return 0;
                        }
                        sbi->s_jquota_fmt = qfmt;
@@ -1395,8 +1443,8 @@ set_qf_format:
                        break;
                case Opt_noquota:
                        if (sb_any_quota_loaded(sb)) {
-                               printk(KERN_ERR "EXT4-fs: Cannot change quota "
-                                       "options when quota turned on.\n");
+                               ext4_msg(sb, KERN_ERR, "Cannot change quota "
+                                       "options when quota turned on");
                                return 0;
                        }
                        clear_opt(sbi->s_mount_opt, QUOTA);
@@ -1407,8 +1455,8 @@ set_qf_format:
                case Opt_quota:
                case Opt_usrquota:
                case Opt_grpquota:
-                       printk(KERN_ERR
-                               "EXT4-fs: quota options not supported.\n");
+                       ext4_msg(sb, KERN_ERR,
+                               "quota options not supported");
                        break;
                case Opt_usrjquota:
                case Opt_grpjquota:
@@ -1416,9 +1464,8 @@ set_qf_format:
                case Opt_offgrpjquota:
                case Opt_jqfmt_vfsold:
                case Opt_jqfmt_vfsv0:
-                       printk(KERN_ERR
-                               "EXT4-fs: journaled quota options not "
-                               "supported.\n");
+                       ext4_msg(sb, KERN_ERR,
+                               "journaled quota options not supported");
                        break;
                case Opt_noquota:
                        break;
@@ -1443,8 +1490,9 @@ set_qf_format:
                        break;
                case Opt_resize:
                        if (!is_remount) {
-                               printk("EXT4-fs: resize option only available "
-                                       "for remount\n");
+                               ext4_msg(sb, KERN_ERR,
+                                       "resize option only available "
+                                       "for remount");
                                return 0;
                        }
                        if (match_int(&args[0], &option) != 0)
@@ -1474,14 +1522,21 @@ set_qf_format:
                case Opt_delalloc:
                        set_opt(sbi->s_mount_opt, DELALLOC);
                        break;
+               case Opt_block_validity:
+                       set_opt(sbi->s_mount_opt, BLOCK_VALIDITY);
+                       break;
+               case Opt_noblock_validity:
+                       clear_opt(sbi->s_mount_opt, BLOCK_VALIDITY);
+                       break;
                case Opt_inode_readahead_blks:
                        if (match_int(&args[0], &option))
                                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");
+                       if (!is_power_of_2(option)) {
+                               ext4_msg(sb, KERN_ERR,
+                                        "EXT4-fs: inode_readahead_blks"
+                                        " must be a power of 2");
                                return 0;
                        }
                        sbi->s_inode_readahead_blks = option;
@@ -1508,9 +1563,9 @@ set_qf_format:
                                set_opt(sbi->s_mount_opt,NO_AUTO_DA_ALLOC);
                        break;
                default:
-                       printk(KERN_ERR
-                              "EXT4-fs: Unrecognized mount option \"%s\" "
-                              "or missing value\n", p);
+                       ext4_msg(sb, KERN_ERR,
+                              "Unrecognized mount option \"%s\" "
+                              "or missing value", p);
                        return 0;
                }
        }
@@ -1528,21 +1583,21 @@ set_qf_format:
                                (sbi->s_mount_opt & EXT4_MOUNT_GRPQUOTA)) ||
                    (sbi->s_qf_names[GRPQUOTA] &&
                                (sbi->s_mount_opt & EXT4_MOUNT_USRQUOTA))) {
-                       printk(KERN_ERR "EXT4-fs: old and new quota "
-                                       "format mixing.\n");
+                       ext4_msg(sb, KERN_ERR, "old and new quota "
+                                       "format mixing");
                        return 0;
                }
 
                if (!sbi->s_jquota_fmt) {
-                       printk(KERN_ERR "EXT4-fs: journaled quota format "
-                                       "not specified.\n");
+                       ext4_msg(sb, KERN_ERR, "journaled quota format "
+                                       "not specified");
                        return 0;
                }
        } else {
                if (sbi->s_jquota_fmt) {
-                       printk(KERN_ERR "EXT4-fs: journaled quota format "
+                       ext4_msg(sb, KERN_ERR, "journaled quota format "
                                        "specified with no journaling "
-                                       "enabled.\n");
+                                       "enabled");
                        return 0;
                }
        }
@@ -1557,32 +1612,32 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
        int res = 0;
 
        if (le32_to_cpu(es->s_rev_level) > EXT4_MAX_SUPP_REV) {
-               printk(KERN_ERR "EXT4-fs warning: revision level too high, "
-                      "forcing read-only mode\n");
+               ext4_msg(sb, KERN_ERR, "revision level too high, "
+                        "forcing read-only mode");
                res = MS_RDONLY;
        }
        if (read_only)
                return res;
        if (!(sbi->s_mount_state & EXT4_VALID_FS))
-               printk(KERN_WARNING "EXT4-fs warning: mounting unchecked fs, "
-                      "running e2fsck is recommended\n");
+               ext4_msg(sb, KERN_WARNING, "warning: mounting unchecked fs, "
+                        "running e2fsck is recommended");
        else if ((sbi->s_mount_state & EXT4_ERROR_FS))
-               printk(KERN_WARNING
-                      "EXT4-fs warning: mounting fs with errors, "
-                      "running e2fsck is recommended\n");
+               ext4_msg(sb, KERN_WARNING,
+                        "warning: mounting fs with errors, "
+                        "running e2fsck is recommended");
        else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
                 le16_to_cpu(es->s_mnt_count) >=
                 (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
-               printk(KERN_WARNING
-                      "EXT4-fs warning: maximal mount count reached, "
-                      "running e2fsck is recommended\n");
+               ext4_msg(sb, KERN_WARNING,
+                        "warning: maximal mount count reached, "
+                        "running e2fsck is recommended");
        else if (le32_to_cpu(es->s_checkinterval) &&
                (le32_to_cpu(es->s_lastcheck) +
                        le32_to_cpu(es->s_checkinterval) <= get_seconds()))
-               printk(KERN_WARNING
-                      "EXT4-fs warning: checktime reached, "
-                      "running e2fsck is recommended\n");
-       if (!sbi->s_journal) 
+               ext4_msg(sb, KERN_WARNING,
+                        "warning: checktime reached, "
+                        "running e2fsck is recommended");
+       if (!sbi->s_journal)
                es->s_state &= cpu_to_le16(~EXT4_VALID_FS);
        if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
                es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT);
@@ -1592,7 +1647,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
        if (sbi->s_journal)
                EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
 
-       ext4_commit_super(sb, es, 1);
+       ext4_commit_super(sb, 1);
        if (test_opt(sb, DEBUG))
                printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, "
                                "bpg=%lu, ipg=%lu, mo=%04lx]\n",
@@ -1603,11 +1658,11 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
                        sbi->s_mount_opt);
 
        if (EXT4_SB(sb)->s_journal) {
-               printk(KERN_INFO "EXT4 FS on %s, %s journal on %s\n",
-                      sb->s_id, EXT4_SB(sb)->s_journal->j_inode ? "internal" :
+               ext4_msg(sb, KERN_INFO, "%s journal on %s",
+                      EXT4_SB(sb)->s_journal->j_inode ? "internal" :
                       "external", EXT4_SB(sb)->s_journal->j_devname);
        } else {
-               printk(KERN_INFO "EXT4 FS on %s, no journal\n", sb->s_id);
+               ext4_msg(sb, KERN_INFO, "no journal");
        }
        return res;
 }
@@ -1616,10 +1671,10 @@ static int ext4_fill_flex_info(struct super_block *sb)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct ext4_group_desc *gdp = NULL;
-       struct buffer_head *bh;
        ext4_group_t flex_group_count;
        ext4_group_t flex_group;
        int groups_per_flex = 0;
+       size_t size;
        int i;
 
        if (!sbi->s_es->s_log_groups_per_flex) {
@@ -1634,16 +1689,21 @@ static int ext4_fill_flex_info(struct super_block *sb)
        flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) +
                        ((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) <<
                              EXT4_DESC_PER_BLOCK_BITS(sb))) / groups_per_flex;
-       sbi->s_flex_groups = kzalloc(flex_group_count *
-                                    sizeof(struct flex_groups), GFP_KERNEL);
+       size = flex_group_count * sizeof(struct flex_groups);
+       sbi->s_flex_groups = kzalloc(size, GFP_KERNEL);
+       if (sbi->s_flex_groups == NULL) {
+               sbi->s_flex_groups = vmalloc(size);
+               if (sbi->s_flex_groups)
+                       memset(sbi->s_flex_groups, 0, size);
+       }
        if (sbi->s_flex_groups == NULL) {
-               printk(KERN_ERR "EXT4-fs: not enough memory for "
-                               "%u flex groups\n", flex_group_count);
+               ext4_msg(sb, KERN_ERR, "not enough memory for "
+                               "%u flex groups", flex_group_count);
                goto failed;
        }
 
        for (i = 0; i < sbi->s_groups_count; i++) {
-               gdp = ext4_get_group_desc(sb, i, &bh);
+               gdp = ext4_get_group_desc(sb, i, NULL);
 
                flex_group = ext4_flex_group(sbi, i);
                atomic_set(&sbi->s_flex_groups[flex_group].free_inodes,
@@ -1724,44 +1784,44 @@ static int ext4_check_descriptors(struct super_block *sb)
 
                block_bitmap = ext4_block_bitmap(sb, gdp);
                if (block_bitmap < first_block || block_bitmap > last_block) {
-                       printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
+                       ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
                               "Block bitmap for group %u not in group "
-                              "(block %llu)!\n", i, block_bitmap);
+                              "(block %llu)!", i, block_bitmap);
                        return 0;
                }
                inode_bitmap = ext4_inode_bitmap(sb, gdp);
                if (inode_bitmap < first_block || inode_bitmap > last_block) {
-                       printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
+                       ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
                               "Inode bitmap for group %u not in group "
-                              "(block %llu)!\n", i, inode_bitmap);
+                              "(block %llu)!", i, inode_bitmap);
                        return 0;
                }
                inode_table = ext4_inode_table(sb, gdp);
                if (inode_table < first_block ||
                    inode_table + sbi->s_itb_per_group - 1 > last_block) {
-                       printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
+                       ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
                               "Inode table for group %u not in group "
-                              "(block %llu)!\n", i, inode_table);
+                              "(block %llu)!", i, inode_table);
                        return 0;
                }
-               spin_lock(sb_bgl_lock(sbi, i));
+               ext4_lock_group(sb, i);
                if (!ext4_group_desc_csum_verify(sbi, i, gdp)) {
-                       printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
-                              "Checksum for group %u failed (%u!=%u)\n",
-                              i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
-                              gdp)), le16_to_cpu(gdp->bg_checksum));
+                       ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
+                                "Checksum for group %u failed (%u!=%u)",
+                                i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
+                                    gdp)), le16_to_cpu(gdp->bg_checksum));
                        if (!(sb->s_flags & MS_RDONLY)) {
-                               spin_unlock(sb_bgl_lock(sbi, i));
+                               ext4_unlock_group(sb, i);
                                return 0;
                        }
                }
-               spin_unlock(sb_bgl_lock(sbi, i));
+               ext4_unlock_group(sb, i);
                if (!flexbg_flag)
                        first_block += EXT4_BLOCKS_PER_GROUP(sb);
        }
 
        ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
-       sbi->s_es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb));
+       sbi->s_es->s_free_inodes_count =cpu_to_le32(ext4_count_free_inodes(sb));
        return 1;
 }
 
@@ -1796,8 +1856,8 @@ static void ext4_orphan_cleanup(struct super_block *sb,
        }
 
        if (bdev_read_only(sb->s_bdev)) {
-               printk(KERN_ERR "EXT4-fs: write access "
-                       "unavailable, skipping orphan cleanup.\n");
+               ext4_msg(sb, KERN_ERR, "write access "
+                       "unavailable, skipping orphan cleanup");
                return;
        }
 
@@ -1811,8 +1871,7 @@ static void ext4_orphan_cleanup(struct super_block *sb,
        }
 
        if (s_flags & MS_RDONLY) {
-               printk(KERN_INFO "EXT4-fs: %s: orphan cleanup on readonly fs\n",
-                      sb->s_id);
+               ext4_msg(sb, KERN_INFO, "orphan cleanup on readonly fs");
                sb->s_flags &= ~MS_RDONLY;
        }
 #ifdef CONFIG_QUOTA
@@ -1823,9 +1882,9 @@ static void ext4_orphan_cleanup(struct super_block *sb,
                if (EXT4_SB(sb)->s_qf_names[i]) {
                        int ret = ext4_quota_on_mount(sb, i);
                        if (ret < 0)
-                               printk(KERN_ERR
-                                       "EXT4-fs: Cannot turn on journaled "
-                                       "quota: error %d\n", ret);
+                               ext4_msg(sb, KERN_ERR,
+                                       "Cannot turn on journaled "
+                                       "quota: error %d", ret);
                }
        }
 #endif
@@ -1842,16 +1901,16 @@ static void ext4_orphan_cleanup(struct super_block *sb,
                list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan);
                vfs_dq_init(inode);
                if (inode->i_nlink) {
-                       printk(KERN_DEBUG
-                               "%s: truncating inode %lu to %lld bytes\n",
+                       ext4_msg(sb, KERN_DEBUG,
+                               "%s: truncating inode %lu to %lld bytes",
                                __func__, inode->i_ino, inode->i_size);
                        jbd_debug(2, "truncating inode %lu to %lld bytes\n",
                                  inode->i_ino, inode->i_size);
                        ext4_truncate(inode);
                        nr_truncates++;
                } else {
-                       printk(KERN_DEBUG
-                               "%s: deleting unreferenced inode %lu\n",
+                       ext4_msg(sb, KERN_DEBUG,
+                               "%s: deleting unreferenced inode %lu",
                                __func__, inode->i_ino);
                        jbd_debug(2, "deleting unreferenced inode %lu\n",
                                  inode->i_ino);
@@ -1863,11 +1922,11 @@ static void ext4_orphan_cleanup(struct super_block *sb,
 #define PLURAL(x) (x), ((x) == 1) ? "" : "s"
 
        if (nr_orphans)
-               printk(KERN_INFO "EXT4-fs: %s: %d orphan inode%s deleted\n",
-                      sb->s_id, PLURAL(nr_orphans));
+               ext4_msg(sb, KERN_INFO, "%d orphan inode%s deleted",
+                      PLURAL(nr_orphans));
        if (nr_truncates)
-               printk(KERN_INFO "EXT4-fs: %s: %d truncate%s cleaned up\n",
-                      sb->s_id, PLURAL(nr_truncates));
+               ext4_msg(sb, KERN_INFO, "%d truncate%s cleaned up",
+                      PLURAL(nr_truncates));
 #ifdef CONFIG_QUOTA
        /* Turn quotas off */
        for (i = 0; i < MAXQUOTAS; i++) {
@@ -1877,6 +1936,7 @@ static void ext4_orphan_cleanup(struct super_block *sb,
 #endif
        sb->s_flags = s_flags; /* Restore MS_RDONLY status */
 }
+
 /*
  * Maximal extent format file size.
  * Resulting logical blkno at s_maxbytes must fit in our on-disk
@@ -1927,19 +1987,19 @@ static loff_t ext4_max_bitmap_size(int bits, int has_huge_files)
        loff_t res = EXT4_NDIR_BLOCKS;
        int meta_blocks;
        loff_t upper_limit;
-       /* This is calculated to be the largest file size for a
-        * dense, bitmapped file such that the total number of
-        * sectors in the file, including data and all indirect blocks,
-        * does not exceed 2^48 -1
-        * __u32 i_blocks_lo and _u16 i_blocks_high representing the
-        * total number of  512 bytes blocks of the file
+       /* This is calculated to be the largest file size for a dense, block
+        * mapped file such that the file's total number of 512-byte sectors,
+        * including data and all indirect blocks, does not exceed (2^48 - 1).
+        *
+        * __u32 i_blocks_lo and _u16 i_blocks_high represent the total
+        * number of 512-byte sectors of the file.
         */
 
        if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) {
                /*
-                * !has_huge_files or CONFIG_LBD is not enabled
-                * implies the inode i_block represent total blocks in
-                * 512 bytes 32 == size of vfs inode i_blocks * 8
+                * !has_huge_files or CONFIG_LBD not enabled implies that
+                * the inode i_block field represents total file blocks in
+                * 2^32 512-byte sectors == size of vfs inode i_blocks * 8
                 */
                upper_limit = (1LL << 32) - 1;
 
@@ -1981,7 +2041,7 @@ static loff_t ext4_max_bitmap_size(int bits, int has_huge_files)
 }
 
 static ext4_fsblk_t descriptor_loc(struct super_block *sb,
-                               ext4_fsblk_t logical_sb_block, int nr)
+                                  ext4_fsblk_t logical_sb_block, int nr)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        ext4_group_t bg, first_meta_bg;
@@ -1995,6 +2055,7 @@ static ext4_fsblk_t descriptor_loc(struct super_block *sb,
        bg = sbi->s_desc_per_block * nr;
        if (ext4_bg_has_super(sb, bg))
                has_super = 1;
+
        return (has_super + ext4_group_first_block_no(sb, bg));
 }
 
@@ -2091,8 +2152,7 @@ static ssize_t inode_readahead_blks_store(struct ext4_attr *a,
        if (parse_strtoul(buf, 0x40000000, &t))
                return -EINVAL;
 
-       /* inode_readahead_blks must be a power of 2 */
-       if (t & (t-1))
+       if (!is_power_of_2(t))
                return -EINVAL;
 
        sbi->s_inode_readahead_blks = t;
@@ -2100,7 +2160,7 @@ static ssize_t inode_readahead_blks_store(struct ext4_attr *a,
 }
 
 static ssize_t sbi_ui_show(struct ext4_attr *a,
-                               struct ext4_sb_info *sbi, char *buf)
+                          struct ext4_sb_info *sbi, char *buf)
 {
        unsigned int *ui = (unsigned int *) (((char *) sbi) + a->offset);
 
@@ -2205,7 +2265,6 @@ static struct kobj_type ext4_ktype = {
 static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                                __releases(kernel_lock)
                                __acquires(kernel_lock)
-
 {
        struct buffer_head *bh;
        struct ext4_super_block *es = NULL;
@@ -2256,7 +2315,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 
        blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE);
        if (!blocksize) {
-               printk(KERN_ERR "EXT4-fs: unable to set blocksize\n");
+               ext4_msg(sb, KERN_ERR, "unable to set blocksize");
                goto out_fail;
        }
 
@@ -2272,7 +2331,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        if (!(bh = sb_bread(sb, logical_sb_block))) {
-               printk(KERN_ERR "EXT4-fs: unable to read superblock\n");
+               ext4_msg(sb, KERN_ERR, "unable to read superblock");
                goto out_fail;
        }
        /*
@@ -2321,6 +2380,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_commit_interval = JBD2_DEFAULT_MAX_COMMIT_AGE * HZ;
        sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME;
        sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME;
+       sbi->s_mb_history_max = default_mb_history_length;
 
        set_opt(sbi->s_mount_opt, BARRIER);
 
@@ -2330,7 +2390,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
         */
        set_opt(sbi->s_mount_opt, DELALLOC);
 
-
        if (!parse_options((char *) data, sb, &journal_devnum,
                           &journal_ioprio, NULL, 0))
                goto failed_mount;
@@ -2342,9 +2401,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
            (EXT4_HAS_COMPAT_FEATURE(sb, ~0U) ||
             EXT4_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
             EXT4_HAS_INCOMPAT_FEATURE(sb, ~0U)))
-               printk(KERN_WARNING
-                      "EXT4-fs warning: feature flags set on rev 0 fs, "
-                      "running e2fsck is recommended\n");
+               ext4_msg(sb, KERN_WARNING,
+                      "feature flags set on rev 0 fs, "
+                      "running e2fsck is recommended");
 
        /*
         * Check feature flags regardless of the revision level, since we
@@ -2353,16 +2412,18 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
         */
        features = EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT4_FEATURE_INCOMPAT_SUPP);
        if (features) {
-               printk(KERN_ERR "EXT4-fs: %s: couldn't mount because of "
-                      "unsupported optional features (%x).\n", sb->s_id,
+               ext4_msg(sb, KERN_ERR,
+                       "Couldn't mount because of "
+                       "unsupported optional features (%x)",
                        (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_incompat) &
                        ~EXT4_FEATURE_INCOMPAT_SUPP));
                goto failed_mount;
        }
        features = EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT4_FEATURE_RO_COMPAT_SUPP);
        if (!(sb->s_flags & MS_RDONLY) && features) {
-               printk(KERN_ERR "EXT4-fs: %s: couldn't mount RDWR because of "
-                      "unsupported optional features (%x).\n", sb->s_id,
+               ext4_msg(sb, KERN_ERR,
+                       "Couldn't mount RDWR because of "
+                       "unsupported optional features (%x)",
                        (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_ro_compat) &
                        ~EXT4_FEATURE_RO_COMPAT_SUPP));
                goto failed_mount;
@@ -2376,9 +2437,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                 */
                if (sizeof(root->i_blocks) < sizeof(u64) &&
                                !(sb->s_flags & MS_RDONLY)) {
-                       printk(KERN_ERR "EXT4-fs: %s: Filesystem with huge "
+                       ext4_msg(sb, KERN_ERR, "Filesystem with huge "
                                        "files cannot be mounted read-write "
-                                       "without CONFIG_LBD.\n", sb->s_id);
+                                       "without CONFIG_LBD");
                        goto failed_mount;
                }
        }
@@ -2386,17 +2447,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 
        if (blocksize < EXT4_MIN_BLOCK_SIZE ||
            blocksize > EXT4_MAX_BLOCK_SIZE) {
-               printk(KERN_ERR
-                      "EXT4-fs: Unsupported filesystem blocksize %d on %s.\n",
-                      blocksize, sb->s_id);
+               ext4_msg(sb, KERN_ERR,
+                      "Unsupported filesystem blocksize %d", blocksize);
                goto failed_mount;
        }
 
        if (sb->s_blocksize != blocksize) {
-
                /* Validate the filesystem blocksize */
                if (!sb_set_blocksize(sb, blocksize)) {
-                       printk(KERN_ERR "EXT4-fs: bad block size %d.\n",
+                       ext4_msg(sb, KERN_ERR, "bad block size %d",
                                        blocksize);
                        goto failed_mount;
                }
@@ -2406,15 +2465,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                offset = do_div(logical_sb_block, blocksize);
                bh = sb_bread(sb, logical_sb_block);
                if (!bh) {
-                       printk(KERN_ERR
-                              "EXT4-fs: Can't read superblock on 2nd try.\n");
+                       ext4_msg(sb, KERN_ERR,
+                              "Can't read superblock on 2nd try");
                        goto failed_mount;
                }
                es = (struct ext4_super_block *)(((char *)bh->b_data) + offset);
                sbi->s_es = es;
                if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) {
-                       printk(KERN_ERR
-                              "EXT4-fs: Magic mismatch, very weird !\n");
+                       ext4_msg(sb, KERN_ERR,
+                              "Magic mismatch, very weird!");
                        goto failed_mount;
                }
        }
@@ -2432,30 +2491,33 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) ||
                    (!is_power_of_2(sbi->s_inode_size)) ||
                    (sbi->s_inode_size > blocksize)) {
-                       printk(KERN_ERR
-                              "EXT4-fs: unsupported inode size: %d\n",
+                       ext4_msg(sb, KERN_ERR,
+                              "unsupported inode size: %d",
                               sbi->s_inode_size);
                        goto failed_mount;
                }
                if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE)
                        sb->s_time_gran = 1 << (EXT4_EPOCH_BITS - 2);
        }
+
        sbi->s_desc_size = le16_to_cpu(es->s_desc_size);
        if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT)) {
                if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT ||
                    sbi->s_desc_size > EXT4_MAX_DESC_SIZE ||
                    !is_power_of_2(sbi->s_desc_size)) {
-                       printk(KERN_ERR
-                              "EXT4-fs: unsupported descriptor size %lu\n",
+                       ext4_msg(sb, KERN_ERR,
+                              "unsupported descriptor size %lu",
                               sbi->s_desc_size);
                        goto failed_mount;
                }
        } else
                sbi->s_desc_size = EXT4_MIN_DESC_SIZE;
+
        sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
        sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
        if (EXT4_INODE_SIZE(sb) == 0 || EXT4_INODES_PER_GROUP(sb) == 0)
                goto cantfind_ext4;
+
        sbi->s_inodes_per_block = blocksize / EXT4_INODE_SIZE(sb);
        if (sbi->s_inodes_per_block == 0)
                goto cantfind_ext4;
@@ -2466,6 +2528,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_mount_state = le16_to_cpu(es->s_state);
        sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb));
        sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb));
+
        for (i = 0; i < 4; i++)
                sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
        sbi->s_def_hash_version = es->s_def_hash_version;
@@ -2483,25 +2546,24 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        if (sbi->s_blocks_per_group > blocksize * 8) {
-               printk(KERN_ERR
-                      "EXT4-fs: #blocks per group too big: %lu\n",
+               ext4_msg(sb, KERN_ERR,
+                      "#blocks per group too big: %lu",
                       sbi->s_blocks_per_group);
                goto failed_mount;
        }
        if (sbi->s_inodes_per_group > blocksize * 8) {
-               printk(KERN_ERR
-                      "EXT4-fs: #inodes per group too big: %lu\n",
+               ext4_msg(sb, KERN_ERR,
+                      "#inodes per group too big: %lu",
                       sbi->s_inodes_per_group);
                goto failed_mount;
        }
 
        if (ext4_blocks_count(es) >
                    (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
-               printk(KERN_ERR "EXT4-fs: filesystem on %s:"
-                       " too large to mount safely\n", sb->s_id);
+               ext4_msg(sb, KERN_ERR, "filesystem"
+                       " too large to mount safely");
                if (sizeof(sector_t) < 8)
-                       printk(KERN_WARNING "EXT4-fs: CONFIG_LBD not "
-                                       "enabled\n");
+                       ext4_msg(sb, KERN_WARNING, "CONFIG_LBD not enabled");
                goto failed_mount;
        }
 
@@ -2511,21 +2573,21 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        /* check blocks count against device size */
        blocks_count = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits;
        if (blocks_count && ext4_blocks_count(es) > blocks_count) {
-               printk(KERN_WARNING "EXT4-fs: bad geometry: block count %llu "
-                      "exceeds size of device (%llu blocks)\n",
+               ext4_msg(sb, KERN_WARNING, "bad geometry: block count %llu "
+                      "exceeds size of device (%llu blocks)",
                       ext4_blocks_count(es), blocks_count);
                goto failed_mount;
        }
 
-        /*
-         * It makes no sense for the first data block to be beyond the end
-         * of the filesystem.
-         */
-        if (le32_to_cpu(es->s_first_data_block) >= ext4_blocks_count(es)) {
-                printk(KERN_WARNING "EXT4-fs: bad geometry: first data"
-                      "block %u is beyond end of filesystem (%llu)\n",
-                      le32_to_cpu(es->s_first_data_block),
-                      ext4_blocks_count(es));
+       /*
+        * It makes no sense for the first data block to be beyond the end
+        * of the filesystem.
+        */
+       if (le32_to_cpu(es->s_first_data_block) >= ext4_blocks_count(es)) {
+                ext4_msg(sb, KERN_WARNING, "bad geometry: first data"
+                        "block %u is beyond end of filesystem (%llu)",
+                        le32_to_cpu(es->s_first_data_block),
+                        ext4_blocks_count(es));
                goto failed_mount;
        }
        blocks_count = (ext4_blocks_count(es) -
@@ -2533,9 +2595,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                        EXT4_BLOCKS_PER_GROUP(sb) - 1);
        do_div(blocks_count, EXT4_BLOCKS_PER_GROUP(sb));
        if (blocks_count > ((uint64_t)1<<32) - EXT4_DESC_PER_BLOCK(sb)) {
-               printk(KERN_WARNING "EXT4-fs: groups count too large: %u "
+               ext4_msg(sb, KERN_WARNING, "groups count too large: %u "
                       "(block count %llu, first data block %u, "
-                      "blocks per group %lu)\n", sbi->s_groups_count,
+                      "blocks per group %lu)", sbi->s_groups_count,
                       ext4_blocks_count(es),
                       le32_to_cpu(es->s_first_data_block),
                       EXT4_BLOCKS_PER_GROUP(sb));
@@ -2547,7 +2609,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_group_desc = kmalloc(db_count * sizeof(struct buffer_head *),
                                    GFP_KERNEL);
        if (sbi->s_group_desc == NULL) {
-               printk(KERN_ERR "EXT4-fs: not enough memory\n");
+               ext4_msg(sb, KERN_ERR, "not enough memory");
                goto failed_mount;
        }
 
@@ -2562,21 +2624,21 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                block = descriptor_loc(sb, logical_sb_block, i);
                sbi->s_group_desc[i] = sb_bread(sb, block);
                if (!sbi->s_group_desc[i]) {
-                       printk(KERN_ERR "EXT4-fs: "
-                              "can't read group descriptor %d\n", i);
+                       ext4_msg(sb, KERN_ERR,
+                              "can't read group descriptor %d", i);
                        db_count = i;
                        goto failed_mount2;
                }
        }
        if (!ext4_check_descriptors(sb)) {
-               printk(KERN_ERR "EXT4-fs: group descriptors corrupted!\n");
+               ext4_msg(sb, KERN_ERR, "group descriptors corrupted!");
                goto failed_mount2;
        }
        if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
                if (!ext4_fill_flex_info(sb)) {
-                       printk(KERN_ERR
-                              "EXT4-fs: unable to initialize "
-                              "flex_bg meta info!\n");
+                       ext4_msg(sb, KERN_ERR,
+                              "unable to initialize "
+                              "flex_bg meta info!");
                        goto failed_mount2;
                }
 
@@ -2598,7 +2660,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
        }
        if (err) {
-               printk(KERN_ERR "EXT4-fs: insufficient memory\n");
+               ext4_msg(sb, KERN_ERR, "insufficient memory");
                goto failed_mount3;
        }
 
@@ -2607,7 +2669,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        /*
         * set up enough so that it can read an inode
         */
-       sb->s_op = &ext4_sops;
+       if (!test_opt(sb, NOLOAD) &&
+           EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL))
+               sb->s_op = &ext4_sops;
+       else
+               sb->s_op = &ext4_nojournal_sops;
        sb->s_export_op = &ext4_export_ops;
        sb->s_xattr = ext4_xattr_handlers;
 #ifdef CONFIG_QUOTA
@@ -2615,6 +2681,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sb->dq_op = &ext4_quota_operations;
 #endif
        INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
+       mutex_init(&sbi->s_orphan_lock);
+       mutex_init(&sbi->s_resize_lock);
 
        sb->s_root = NULL;
 
@@ -2632,13 +2700,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                        goto failed_mount3;
                if (!(sb->s_flags & MS_RDONLY) &&
                    EXT4_SB(sb)->s_journal->j_failed_commit) {
-                       printk(KERN_CRIT "EXT4-fs error (device %s): "
+                       ext4_msg(sb, KERN_CRIT, "error: "
                               "ext4_fill_super: Journal transaction "
-                              "%u is corrupt\n", sb->s_id,
+                              "%u is corrupt",
                               EXT4_SB(sb)->s_journal->j_failed_commit);
                        if (test_opt(sb, ERRORS_RO)) {
-                               printk(KERN_CRIT
-                                      "Mounting filesystem read-only\n");
+                               ext4_msg(sb, KERN_CRIT,
+                                      "Mounting filesystem read-only");
                                sb->s_flags |= MS_RDONLY;
                                EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
                                es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
@@ -2646,14 +2714,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                        if (test_opt(sb, ERRORS_PANIC)) {
                                EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
                                es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
-                               ext4_commit_super(sb, es, 1);
+                               ext4_commit_super(sb, 1);
                                goto failed_mount4;
                        }
                }
        } else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) &&
              EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) {
-               printk(KERN_ERR "EXT4-fs: required journal recovery "
-                      "suppressed and not mounted read-only\n");
+               ext4_msg(sb, KERN_ERR, "required journal recovery "
+                      "suppressed and not mounted read-only");
                goto failed_mount4;
        } else {
                clear_opt(sbi->s_mount_opt, DATA_FLAGS);
@@ -2666,7 +2734,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        if (ext4_blocks_count(es) > 0xffffffffULL &&
            !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0,
                                       JBD2_FEATURE_INCOMPAT_64BIT)) {
-               printk(KERN_ERR "EXT4-fs: Failed to set 64-bit journal feature\n");
+               ext4_msg(sb, KERN_ERR, "Failed to set 64-bit journal feature");
                goto failed_mount4;
        }
 
@@ -2704,8 +2772,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        case EXT4_MOUNT_WRITEBACK_DATA:
                if (!jbd2_journal_check_available_features
                    (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)) {
-                       printk(KERN_ERR "EXT4-fs: Journal does not support "
-                              "requested data journaling mode\n");
+                       ext4_msg(sb, KERN_ERR, "Journal does not support "
+                              "requested data journaling mode");
                        goto failed_mount4;
                }
        default:
@@ -2717,8 +2785,8 @@ no_journal:
 
        if (test_opt(sb, NOBH)) {
                if (!(test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)) {
-                       printk(KERN_WARNING "EXT4-fs: Ignoring nobh option - "
-                               "its supported only with writeback mode\n");
+                       ext4_msg(sb, KERN_WARNING, "Ignoring nobh option - "
+                               "its supported only with writeback mode");
                        clear_opt(sbi->s_mount_opt, NOBH);
                }
        }
@@ -2729,18 +2797,18 @@ no_journal:
 
        root = ext4_iget(sb, EXT4_ROOT_INO);
        if (IS_ERR(root)) {
-               printk(KERN_ERR "EXT4-fs: get root inode failed\n");
+               ext4_msg(sb, KERN_ERR, "get root inode failed");
                ret = PTR_ERR(root);
                goto failed_mount4;
        }
        if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
                iput(root);
-               printk(KERN_ERR "EXT4-fs: corrupt root inode, run e2fsck\n");
+               ext4_msg(sb, KERN_ERR, "corrupt root inode, run e2fsck");
                goto failed_mount4;
        }
        sb->s_root = d_alloc_root(root);
        if (!sb->s_root) {
-               printk(KERN_ERR "EXT4-fs: get root dentry failed\n");
+               ext4_msg(sb, KERN_ERR, "get root dentry failed");
                iput(root);
                ret = -ENOMEM;
                goto failed_mount4;
@@ -2769,22 +2837,29 @@ no_journal:
                                                        sbi->s_inode_size) {
                sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
                                                       EXT4_GOOD_OLD_INODE_SIZE;
-               printk(KERN_INFO "EXT4-fs: required extra inode space not"
-                       "available.\n");
+               ext4_msg(sb, KERN_INFO, "required extra inode space not"
+                        "available");
        }
 
        if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
-               printk(KERN_WARNING "EXT4-fs: Ignoring delalloc option - "
-                               "requested data journaling mode\n");
+               ext4_msg(sb, KERN_WARNING, "Ignoring delalloc option - "
+                        "requested data journaling mode");
                clear_opt(sbi->s_mount_opt, DELALLOC);
        } else if (test_opt(sb, DELALLOC))
-               printk(KERN_INFO "EXT4-fs: delayed allocation enabled\n");
+               ext4_msg(sb, KERN_INFO, "delayed allocation enabled");
+
+       err = ext4_setup_system_zone(sb);
+       if (err) {
+               ext4_msg(sb, KERN_ERR, "failed to initialize system "
+                        "zone (%d)\n", err);
+               goto failed_mount4;
+       }
 
        ext4_ext_init(sb);
        err = ext4_mb_init(sb, needs_recovery);
        if (err) {
-               printk(KERN_ERR "EXT4-fs: failed to initalize mballoc (%d)\n",
-                      err);
+               ext4_msg(sb, KERN_ERR, "failed to initalize mballoc (%d)",
+                        err);
                goto failed_mount4;
        }
 
@@ -2798,19 +2873,11 @@ no_journal:
                goto failed_mount4;
        };
 
-       /*
-        * akpm: core read_super() calls in here with the superblock locked.
-        * That deadlocks, because orphan cleanup needs to lock the superblock
-        * in numerous places.  Here we just pop the lock - it's relatively
-        * harmless, because we are now ready to accept write_super() requests,
-        * and aviro says that's the only reason for hanging onto the
-        * superblock lock.
-        */
        EXT4_SB(sb)->s_mount_state |= EXT4_ORPHAN_FS;
        ext4_orphan_cleanup(sb, es);
        EXT4_SB(sb)->s_mount_state &= ~EXT4_ORPHAN_FS;
        if (needs_recovery) {
-               printk(KERN_INFO "EXT4-fs: recovery complete.\n");
+               ext4_msg(sb, KERN_INFO, "recovery complete");
                ext4_mark_recovery_complete(sb, es);
        }
        if (EXT4_SB(sb)->s_journal) {
@@ -2823,25 +2890,30 @@ no_journal:
        } else
                descr = "out journal";
 
-       printk(KERN_INFO "EXT4-fs: mounted filesystem %s with%s\n",
-              sb->s_id, descr);
+       ext4_msg(sb, KERN_INFO, "mounted filesystem with%s", descr);
 
        lock_kernel();
        return 0;
 
 cantfind_ext4:
        if (!silent)
-               printk(KERN_ERR "VFS: Can't find ext4 filesystem on dev %s.\n",
-                      sb->s_id);
+               ext4_msg(sb, KERN_ERR, "VFS: Can't find ext4 filesystem");
        goto failed_mount;
 
 failed_mount4:
-       printk(KERN_ERR "EXT4-fs (device %s): mount failed\n", sb->s_id);
+       ext4_msg(sb, KERN_ERR, "mount failed");
+       ext4_release_system_zone(sb);
        if (sbi->s_journal) {
                jbd2_journal_destroy(sbi->s_journal);
                sbi->s_journal = NULL;
        }
 failed_mount3:
+       if (sbi->s_flex_groups) {
+               if (is_vmalloc_addr(sbi->s_flex_groups))
+                       vfree(sbi->s_flex_groups);
+               else
+                       kfree(sbi->s_flex_groups);
+       }
        percpu_counter_destroy(&sbi->s_freeblocks_counter);
        percpu_counter_destroy(&sbi->s_freeinodes_counter);
        percpu_counter_destroy(&sbi->s_dirs_counter);
@@ -2862,6 +2934,7 @@ failed_mount:
        brelse(bh);
 out_fail:
        sb->s_fs_info = NULL;
+       kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
        lock_kernel();
        return ret;
@@ -2906,27 +2979,27 @@ static journal_t *ext4_get_journal(struct super_block *sb,
 
        journal_inode = ext4_iget(sb, journal_inum);
        if (IS_ERR(journal_inode)) {
-               printk(KERN_ERR "EXT4-fs: no journal found.\n");
+               ext4_msg(sb, KERN_ERR, "no journal found");
                return NULL;
        }
        if (!journal_inode->i_nlink) {
                make_bad_inode(journal_inode);
                iput(journal_inode);
-               printk(KERN_ERR "EXT4-fs: journal inode is deleted.\n");
+               ext4_msg(sb, KERN_ERR, "journal inode is deleted");
                return NULL;
        }
 
        jbd_debug(2, "Journal inode found at %p: %lld bytes\n",
                  journal_inode, journal_inode->i_size);
        if (!S_ISREG(journal_inode->i_mode)) {
-               printk(KERN_ERR "EXT4-fs: invalid journal inode.\n");
+               ext4_msg(sb, KERN_ERR, "invalid journal inode");
                iput(journal_inode);
                return NULL;
        }
 
        journal = jbd2_journal_init_inode(journal_inode);
        if (!journal) {
-               printk(KERN_ERR "EXT4-fs: Could not load journal inode\n");
+               ext4_msg(sb, KERN_ERR, "Could not load journal inode");
                iput(journal_inode);
                return NULL;
        }
@@ -2950,22 +3023,22 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
 
        BUG_ON(!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL));
 
-       bdev = ext4_blkdev_get(j_dev);
+       bdev = ext4_blkdev_get(j_dev, sb);
        if (bdev == NULL)
                return NULL;
 
        if (bd_claim(bdev, sb)) {
-               printk(KERN_ERR
-                       "EXT4-fs: failed to claim external journal device.\n");
+               ext4_msg(sb, KERN_ERR,
+                       "failed to claim external journal device");
                blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
                return NULL;
        }
 
        blocksize = sb->s_blocksize;
-       hblock = bdev_hardsect_size(bdev);
+       hblock = bdev_logical_block_size(bdev);
        if (blocksize < hblock) {
-               printk(KERN_ERR
-                       "EXT4-fs: blocksize too small for journal device.\n");
+               ext4_msg(sb, KERN_ERR,
+                       "blocksize too small for journal device");
                goto out_bdev;
        }
 
@@ -2973,8 +3046,8 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
        offset = EXT4_MIN_BLOCK_SIZE % blocksize;
        set_blocksize(bdev, blocksize);
        if (!(bh = __bread(bdev, sb_block, blocksize))) {
-               printk(KERN_ERR "EXT4-fs: couldn't read superblock of "
-                      "external journal\n");
+               ext4_msg(sb, KERN_ERR, "couldn't read superblock of "
+                      "external journal");
                goto out_bdev;
        }
 
@@ -2982,14 +3055,14 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
        if ((le16_to_cpu(es->s_magic) != EXT4_SUPER_MAGIC) ||
            !(le32_to_cpu(es->s_feature_incompat) &
              EXT4_FEATURE_INCOMPAT_JOURNAL_DEV)) {
-               printk(KERN_ERR "EXT4-fs: external journal has "
-                                       "bad superblock\n");
+               ext4_msg(sb, KERN_ERR, "external journal has "
+                                       "bad superblock");
                brelse(bh);
                goto out_bdev;
        }
 
        if (memcmp(EXT4_SB(sb)->s_es->s_journal_uuid, es->s_uuid, 16)) {
-               printk(KERN_ERR "EXT4-fs: journal UUID does not match\n");
+               ext4_msg(sb, KERN_ERR, "journal UUID does not match");
                brelse(bh);
                goto out_bdev;
        }
@@ -3001,25 +3074,26 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
        journal = jbd2_journal_init_dev(bdev, sb->s_bdev,
                                        start, len, blocksize);
        if (!journal) {
-               printk(KERN_ERR "EXT4-fs: failed to create device journal\n");
+               ext4_msg(sb, KERN_ERR, "failed to create device journal");
                goto out_bdev;
        }
        journal->j_private = sb;
        ll_rw_block(READ, 1, &journal->j_sb_buffer);
        wait_on_buffer(journal->j_sb_buffer);
        if (!buffer_uptodate(journal->j_sb_buffer)) {
-               printk(KERN_ERR "EXT4-fs: I/O error on journal device\n");
+               ext4_msg(sb, KERN_ERR, "I/O error on journal device");
                goto out_journal;
        }
        if (be32_to_cpu(journal->j_superblock->s_nr_users) != 1) {
-               printk(KERN_ERR "EXT4-fs: External journal has more than one "
-                                       "user (unsupported) - %d\n",
+               ext4_msg(sb, KERN_ERR, "External journal has more than one "
+                                       "user (unsupported) - %d",
                        be32_to_cpu(journal->j_superblock->s_nr_users));
                goto out_journal;
        }
        EXT4_SB(sb)->journal_bdev = bdev;
        ext4_init_journal_params(sb, journal);
        return journal;
+
 out_journal:
        jbd2_journal_destroy(journal);
 out_bdev:
@@ -3041,8 +3115,8 @@ static int ext4_load_journal(struct super_block *sb,
 
        if (journal_devnum &&
            journal_devnum != le32_to_cpu(es->s_journal_dev)) {
-               printk(KERN_INFO "EXT4-fs: external journal device major/minor "
-                       "numbers have changed\n");
+               ext4_msg(sb, KERN_INFO, "external journal device major/minor "
+                       "numbers have changed");
                journal_dev = new_decode_dev(journal_devnum);
        } else
                journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev));
@@ -3054,24 +3128,23 @@ static int ext4_load_journal(struct super_block *sb,
         * crash?  For recovery, we need to check in advance whether we
         * can get read-write access to the device.
         */
-
        if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) {
                if (sb->s_flags & MS_RDONLY) {
-                       printk(KERN_INFO "EXT4-fs: INFO: recovery "
-                                       "required on readonly filesystem.\n");
+                       ext4_msg(sb, KERN_INFO, "INFO: recovery "
+                                       "required on readonly filesystem");
                        if (really_read_only) {
-                               printk(KERN_ERR "EXT4-fs: write access "
-                                       "unavailable, cannot proceed.\n");
+                               ext4_msg(sb, KERN_ERR, "write access "
+                                       "unavailable, cannot proceed");
                                return -EROFS;
                        }
-                       printk(KERN_INFO "EXT4-fs: write access will "
-                              "be enabled during recovery.\n");
+                       ext4_msg(sb, KERN_INFO, "write access will "
+                              "be enabled during recovery");
                }
        }
 
        if (journal_inum && journal_dev) {
-               printk(KERN_ERR "EXT4-fs: filesystem has both journal "
-                      "and inode journals!\n");
+               ext4_msg(sb, KERN_ERR, "filesystem has both journal "
+                      "and inode journals!");
                return -EINVAL;
        }
 
@@ -3084,14 +3157,14 @@ static int ext4_load_journal(struct super_block *sb,
        }
 
        if (journal->j_flags & JBD2_BARRIER)
-               printk(KERN_INFO "EXT4-fs: barriers enabled\n");
+               ext4_msg(sb, KERN_INFO, "barriers enabled");
        else
-               printk(KERN_INFO "EXT4-fs: barriers disabled\n");
+               ext4_msg(sb, KERN_INFO, "barriers disabled");
 
        if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) {
                err = jbd2_journal_update_format(journal);
                if (err)  {
-                       printk(KERN_ERR "EXT4-fs: error updating journal.\n");
+                       ext4_msg(sb, KERN_ERR, "error updating journal");
                        jbd2_journal_destroy(journal);
                        return err;
                }
@@ -3103,7 +3176,7 @@ static int ext4_load_journal(struct super_block *sb,
                err = jbd2_journal_load(journal);
 
        if (err) {
-               printk(KERN_ERR "EXT4-fs: error loading journal.\n");
+               ext4_msg(sb, KERN_ERR, "error loading journal");
                jbd2_journal_destroy(journal);
                return err;
        }
@@ -3114,18 +3187,17 @@ static int ext4_load_journal(struct super_block *sb,
        if (journal_devnum &&
            journal_devnum != le32_to_cpu(es->s_journal_dev)) {
                es->s_journal_dev = cpu_to_le32(journal_devnum);
-               sb->s_dirt = 1;
 
                /* Make sure we flush the recovery flag to disk. */
-               ext4_commit_super(sb, es, 1);
+               ext4_commit_super(sb, 1);
        }
 
        return 0;
 }
 
-static int ext4_commit_super(struct super_block *sb,
-                             struct ext4_super_block *es, int sync)
+static int ext4_commit_super(struct super_block *sb, int sync)
 {
+       struct ext4_super_block *es = EXT4_SB(sb)->s_es;
        struct buffer_head *sbh = EXT4_SB(sb)->s_sbh;
        int error = 0;
 
@@ -3140,8 +3212,8 @@ static int ext4_commit_super(struct super_block *sb,
                 * be remapped.  Nothing we can do but to retry the
                 * write and hope for the best.
                 */
-               printk(KERN_ERR "EXT4-fs: previous I/O error to "
-                      "superblock detected for %s.\n", sb->s_id);
+               ext4_msg(sb, KERN_ERR, "previous I/O error to "
+                      "superblock detected");
                clear_buffer_write_io_error(sbh);
                set_buffer_uptodate(sbh);
        }
@@ -3154,7 +3226,7 @@ static int ext4_commit_super(struct super_block *sb,
                                        &EXT4_SB(sb)->s_freeblocks_counter));
        es->s_free_inodes_count = cpu_to_le32(percpu_counter_sum_positive(
                                        &EXT4_SB(sb)->s_freeinodes_counter));
-
+       sb->s_dirt = 0;
        BUFFER_TRACE(sbh, "marking dirty");
        mark_buffer_dirty(sbh);
        if (sync) {
@@ -3164,8 +3236,8 @@ static int ext4_commit_super(struct super_block *sb,
 
                error = buffer_write_io_error(sbh);
                if (error) {
-                       printk(KERN_ERR "EXT4-fs: I/O error while writing "
-                              "superblock for %s.\n", sb->s_id);
+                       ext4_msg(sb, KERN_ERR, "I/O error while writing "
+                              "superblock");
                        clear_buffer_write_io_error(sbh);
                        set_buffer_uptodate(sbh);
                }
@@ -3173,7 +3245,6 @@ static int ext4_commit_super(struct super_block *sb,
        return error;
 }
 
-
 /*
  * Have we just finished recovery?  If so, and if we are mounting (or
  * remounting) the filesystem readonly, then we will end up with a
@@ -3192,14 +3263,11 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
        if (jbd2_journal_flush(journal) < 0)
                goto out;
 
-       lock_super(sb);
        if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) &&
            sb->s_flags & MS_RDONLY) {
                EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
-               sb->s_dirt = 0;
-               ext4_commit_super(sb, es, 1);
+               ext4_commit_super(sb, 1);
        }
-       unlock_super(sb);
 
 out:
        jbd2_journal_unlock_updates(journal);
@@ -3238,7 +3306,7 @@ static void ext4_clear_journal_err(struct super_block *sb,
 
                EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
                es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
-               ext4_commit_super(sb, es, 1);
+               ext4_commit_super(sb, 1);
 
                jbd2_journal_clear_err(journal);
        }
@@ -3257,29 +3325,15 @@ int ext4_force_commit(struct super_block *sb)
                return 0;
 
        journal = EXT4_SB(sb)->s_journal;
-       if (journal) {
-               sb->s_dirt = 0;
+       if (journal)
                ret = ext4_journal_force_commit(journal);
-       }
 
        return ret;
 }
 
-/*
- * Ext4 always journals updates to the superblock itself, so we don't
- * have to propagate any other updates to the superblock on disk at this
- * point.  (We can probably nuke this function altogether, and remove
- * any mention to sb->s_dirt in all of fs/ext4; eventual cleanup...)
- */
 static void ext4_write_super(struct super_block *sb)
 {
-       if (EXT4_SB(sb)->s_journal) {
-               if (mutex_trylock(&sb->s_lock) != 0)
-                       BUG();
-               sb->s_dirt = 0;
-       } else {
-               ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1);
-       }
+       ext4_commit_super(sb, 1);
 }
 
 static int ext4_sync_fs(struct super_block *sb, int wait)
@@ -3288,16 +3342,9 @@ static int ext4_sync_fs(struct super_block *sb, int wait)
        tid_t target;
 
        trace_mark(ext4_sync_fs, "dev %s wait %d", sb->s_id, wait);
-       sb->s_dirt = 0;
-       if (EXT4_SB(sb)->s_journal) {
-               if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal,
-                                             &target)) {
-                       if (wait)
-                               jbd2_log_wait_commit(EXT4_SB(sb)->s_journal,
-                                                    target);
-               }
-       } else {
-               ext4_commit_super(sb, EXT4_SB(sb)->s_es, wait);
+       if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) {
+               if (wait)
+                       jbd2_log_wait_commit(EXT4_SB(sb)->s_journal, target);
        }
        return ret;
 }
@@ -3310,34 +3357,32 @@ static int ext4_freeze(struct super_block *sb)
 {
        int error = 0;
        journal_t *journal;
-       sb->s_dirt = 0;
 
-       if (!(sb->s_flags & MS_RDONLY)) {
-               journal = EXT4_SB(sb)->s_journal;
+       if (sb->s_flags & MS_RDONLY)
+               return 0;
 
-               if (journal) {
-                       /* Now we set up the journal barrier. */
-                       jbd2_journal_lock_updates(journal);
+       journal = EXT4_SB(sb)->s_journal;
 
-                       /*
-                        * We don't want to clear needs_recovery flag when we
-                        * failed to flush the journal.
-                        */
-                       error = jbd2_journal_flush(journal);
-                       if (error < 0)
-                               goto out;
-               }
+       /* Now we set up the journal barrier. */
+       jbd2_journal_lock_updates(journal);
 
-               /* Journal blocked and flushed, clear needs_recovery flag. */
-               EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
-               error = ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1);
-               if (error)
-                       goto out;
+       /*
+        * Don't clear the needs_recovery flag if we failed to flush
+        * the journal.
+        */
+       error = jbd2_journal_flush(journal);
+       if (error < 0) {
+       out:
+               jbd2_journal_unlock_updates(journal);
+               return error;
        }
+
+       /* Journal blocked and flushed, clear needs_recovery flag. */
+       EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+       error = ext4_commit_super(sb, 1);
+       if (error)
+               goto out;
        return 0;
-out:
-       jbd2_journal_unlock_updates(journal);
-       return error;
 }
 
 /*
@@ -3346,14 +3391,15 @@ out:
  */
 static int ext4_unfreeze(struct super_block *sb)
 {
-       if (EXT4_SB(sb)->s_journal && !(sb->s_flags & MS_RDONLY)) {
-               lock_super(sb);
-               /* Reser the needs_recovery flag before the fs is unlocked. */
-               EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
-               ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1);
-               unlock_super(sb);
-               jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
-       }
+       if (sb->s_flags & MS_RDONLY)
+               return 0;
+
+       lock_super(sb);
+       /* Reset the needs_recovery flag before the fs is unlocked. */
+       EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+       ext4_commit_super(sb, 1);
+       unlock_super(sb);
+       jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
        return 0;
 }
 
@@ -3432,22 +3478,15 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                            (sbi->s_mount_state & EXT4_VALID_FS))
                                es->s_state = cpu_to_le16(sbi->s_mount_state);
 
-                       /*
-                        * We have to unlock super so that we can wait for
-                        * transactions.
-                        */
-                       if (sbi->s_journal) {
-                               unlock_super(sb);
+                       if (sbi->s_journal)
                                ext4_mark_recovery_complete(sb, es);
-                               lock_super(sb);
-                       }
                } else {
                        int ret;
                        if ((ret = EXT4_HAS_RO_COMPAT_FEATURE(sb,
                                        ~EXT4_FEATURE_RO_COMPAT_SUPP))) {
-                               printk(KERN_WARNING "EXT4-fs: %s: couldn't "
+                               ext4_msg(sb, KERN_WARNING, "couldn't "
                                       "remount RDWR because of unsupported "
-                                      "optional features (%x).\n", sb->s_id,
+                                      "optional features (%x)",
                                (le32_to_cpu(sbi->s_es->s_feature_ro_compat) &
                                        ~EXT4_FEATURE_RO_COMPAT_SUPP));
                                err = -EROFS;
@@ -3456,17 +3495,15 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 
                        /*
                         * Make sure the group descriptor checksums
-                        * are sane.  If they aren't, refuse to
-                        * remount r/w.
+                        * are sane.  If they aren't, refuse to remount r/w.
                         */
                        for (g = 0; g < sbi->s_groups_count; g++) {
                                struct ext4_group_desc *gdp =
                                        ext4_get_group_desc(sb, g, NULL);
 
                                if (!ext4_group_desc_csum_verify(sbi, g, gdp)) {
-                                       printk(KERN_ERR
-              "EXT4-fs: ext4_remount: "
-               "Checksum for group %u failed (%u!=%u)\n",
+                                       ext4_msg(sb, KERN_ERR,
+              "ext4_remount: Checksum for group %u failed (%u!=%u)",
                g, le16_to_cpu(ext4_group_desc_csum(sbi, g, gdp)),
                                               le16_to_cpu(gdp->bg_checksum));
                                        err = -EINVAL;
@@ -3480,11 +3517,10 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                         * require a full umount/remount for now.
                         */
                        if (es->s_last_orphan) {
-                               printk(KERN_WARNING "EXT4-fs: %s: couldn't "
+                               ext4_msg(sb, KERN_WARNING, "Couldn't "
                                       "remount RDWR because of unprocessed "
                                       "orphan inode list.  Please "
-                                      "umount/remount instead.\n",
-                                      sb->s_id);
+                                      "umount/remount instead");
                                err = -EINVAL;
                                goto restore_opts;
                        }
@@ -3504,8 +3540,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                                sb->s_flags &= ~MS_RDONLY;
                }
        }
+       ext4_setup_system_zone(sb);
        if (sbi->s_journal == NULL)
-               ext4_commit_super(sb, es, 1);
+               ext4_commit_super(sb, 1);
 
 #ifdef CONFIG_QUOTA
        /* Release old quota file names */
@@ -3515,6 +3552,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                        kfree(old_opts.s_qf_names[i]);
 #endif
        return 0;
+
 restore_opts:
        sb->s_flags = old_sb_flags;
        sbi->s_mount_opt = old_opts.s_mount_opt;
@@ -3545,9 +3583,8 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
        if (test_opt(sb, MINIX_DF)) {
                sbi->s_overhead_last = 0;
        } else if (sbi->s_blocks_last != ext4_blocks_count(es)) {
-               ext4_group_t ngroups = sbi->s_groups_count, i;
+               ext4_group_t i, ngroups = ext4_get_groups_count(sb);
                ext4_fsblk_t overhead = 0;
-               smp_rmb();
 
                /*
                 * Compute the overhead (FS structures).  This is constant
@@ -3599,11 +3636,12 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
               le64_to_cpup((void *)es->s_uuid + sizeof(u64));
        buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL;
        buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL;
+
        return 0;
 }
 
-/* Helper function for writing quotas on sync - we need to start transaction before quota file
- * is locked for write. Otherwise the are possible deadlocks:
+/* Helper function for writing quotas on sync - we need to start transaction
+ * before quota file is locked for write. Otherwise the are possible deadlocks:
  * Process 1                         Process 2
  * ext4_create()                     quota_sync()
  *   jbd2_journal_start()                  write_dquot()
@@ -3627,7 +3665,7 @@ static int ext4_write_dquot(struct dquot *dquot)
 
        inode = dquot_to_inode(dquot);
        handle = ext4_journal_start(inode,
-                                       EXT4_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
+                                   EXT4_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
        ret = dquot_commit(dquot);
@@ -3643,7 +3681,7 @@ static int ext4_acquire_dquot(struct dquot *dquot)
        handle_t *handle;
 
        handle = ext4_journal_start(dquot_to_inode(dquot),
-                                       EXT4_QUOTA_INIT_BLOCKS(dquot->dq_sb));
+                                   EXT4_QUOTA_INIT_BLOCKS(dquot->dq_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
        ret = dquot_acquire(dquot);
@@ -3659,7 +3697,7 @@ static int ext4_release_dquot(struct dquot *dquot)
        handle_t *handle;
 
        handle = ext4_journal_start(dquot_to_inode(dquot),
-                                       EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb));
+                                   EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb));
        if (IS_ERR(handle)) {
                /* Release dquot anyway to avoid endless cycle in dqput() */
                dquot_release(dquot);
@@ -3707,7 +3745,7 @@ static int ext4_write_info(struct super_block *sb, int type)
 static int ext4_quota_on_mount(struct super_block *sb, int type)
 {
        return vfs_quota_on_mount(sb, EXT4_SB(sb)->s_qf_names[type],
-                       EXT4_SB(sb)->s_jquota_fmt, type);
+                                 EXT4_SB(sb)->s_jquota_fmt, type);
 }
 
 /*
@@ -3738,9 +3776,9 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
        if (EXT4_SB(sb)->s_qf_names[type]) {
                /* Quotafile not in fs root? */
                if (path.dentry->d_parent != sb->s_root)
-                       printk(KERN_WARNING
-                               "EXT4-fs: Quota file not on filesystem root. "
-                               "Journaled quota will not work.\n");
+                       ext4_msg(sb, KERN_WARNING,
+                               "Quota file not on filesystem root. "
+                               "Journaled quota will not work");
        }
 
        /*
@@ -3823,8 +3861,8 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
        handle_t *handle = journal_current_handle();
 
        if (EXT4_SB(sb)->s_journal && !handle) {
-               printk(KERN_WARNING "EXT4-fs: Quota write (off=%llu, len=%llu)"
-                       " cancelled because transaction is not started.\n",
+               ext4_msg(sb, KERN_WARNING, "Quota write (off=%llu, len=%llu)"
+                       " cancelled because transaction is not started",
                        (unsigned long long)off, (unsigned long long)len);
                return -EIO;
        }
@@ -3878,10 +3916,10 @@ out:
 
 #endif
 
-static int ext4_get_sb(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+static int ext4_get_sb(struct file_system_type *fs_type, int flags,
+                      const char *dev_name, void *data, struct vfsmount *mnt)
 {
-       return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt);
+       return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super,mnt);
 }
 
 static struct file_system_type ext4_fs_type = {
@@ -3893,14 +3931,14 @@ static struct file_system_type ext4_fs_type = {
 };
 
 #ifdef CONFIG_EXT4DEV_COMPAT
-static int ext4dev_get_sb(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+static int ext4dev_get_sb(struct file_system_type *fs_type, int flags,
+                         const char *dev_name, void *data,struct vfsmount *mnt)
 {
-       printk(KERN_WARNING "EXT4-fs: Update your userspace programs "
-              "to mount using ext4\n");
-       printk(KERN_WARNING "EXT4-fs: ext4dev backwards compatibility "
-              "will go away by 2.6.31\n");
-       return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt);
+       printk(KERN_WARNING "EXT4-fs (%s): Update your userspace programs "
+              "to mount using ext4\n", dev_name);
+       printk(KERN_WARNING "EXT4-fs (%s): ext4dev backwards compatibility "
+              "will go away by 2.6.31\n", dev_name);
+       return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super,mnt);
 }
 
 static struct file_system_type ext4dev_fs_type = {
@@ -3917,13 +3955,16 @@ static int __init init_ext4_fs(void)
 {
        int err;
 
+       err = init_ext4_system_zone();
+       if (err)
+               return err;
        ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj);
        if (!ext4_kset)
-               return -ENOMEM;
+               goto out4;
        ext4_proc_root = proc_mkdir("fs/ext4", NULL);
        err = init_ext4_mballoc();
        if (err)
-               return err;
+               goto out3;
 
        err = init_ext4_xattr();
        if (err)
@@ -3948,6 +3989,11 @@ out1:
        exit_ext4_xattr();
 out2:
        exit_ext4_mballoc();
+out3:
+       remove_proc_entry("fs/ext4", NULL);
+       kset_unregister(ext4_kset);
+out4:
+       exit_ext4_system_zone();
        return err;
 }
 
@@ -3962,6 +4008,7 @@ static void __exit exit_ext4_fs(void)
        exit_ext4_mballoc();
        remove_proc_entry("fs/ext4", NULL);
        kset_unregister(ext4_kset);
+       exit_ext4_system_zone();
 }
 
 MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
index 3a981b7f64caf92ce0d48ddba427092e6c212055..cad957cdb1e5ace7f4a65207b0901812075b2fd1 100644 (file)
@@ -7,6 +7,7 @@ config GFS2_FS
        select IP_SCTP if DLM_SCTP
        select FS_POSIX_ACL
        select CRC32
+       select SLOW_WORK
        help
          A cluster filesystem.
 
index a851ea4bdf70331a2b222f19dd7344d6f811e62e..d53a9bea1c2f287f8c68f402a082dece725b3832 100644 (file)
@@ -1,8 +1,8 @@
 obj-$(CONFIG_GFS2_FS) += gfs2.o
 gfs2-y := acl.o bmap.o dir.o eaops.o eattr.o glock.o \
        glops.o inode.o log.o lops.o main.o meta_io.o \
-       mount.o ops_address.o ops_dentry.o ops_export.o ops_file.o \
-       ops_fstype.o ops_inode.o ops_super.o quota.o \
+       aops.o dentry.o export.o file.o \
+       ops_fstype.o ops_inode.o quota.o \
        recovery.o rgrp.o super.o sys.o trans.o util.o
 
 gfs2-$(CONFIG_GFS2_FS_LOCKING_DLM) += lock_dlm.o
similarity index 98%
rename from fs/gfs2/ops_address.c
rename to fs/gfs2/aops.c
index a6dde1751e17dfc48d57979c7d71ab30f755214b..03ebb439ace077847bd31b3d722cd92ee7a07fc1 100644 (file)
@@ -28,7 +28,6 @@
 #include "inode.h"
 #include "log.h"
 #include "meta_io.h"
-#include "ops_address.h"
 #include "quota.h"
 #include "trans.h"
 #include "rgrp.h"
@@ -781,10 +780,12 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
        unlock_page(page);
        page_cache_release(page);
 
-       if (inode->i_size < to) {
-               i_size_write(inode, to);
-               ip->i_disksize = inode->i_size;
-               di->di_size = cpu_to_be64(inode->i_size);
+       if (copied) {
+               if (inode->i_size < to) {
+                       i_size_write(inode, to);
+                       ip->i_disksize = inode->i_size;
+               }
+               gfs2_dinode_out(ip, di);
                mark_inode_dirty(inode);
        }
 
@@ -824,7 +825,6 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
        struct gfs2_sbd *sdp = GFS2_SB(inode);
        struct buffer_head *dibh;
        struct gfs2_alloc *al = ip->i_alloc;
-       struct gfs2_dinode *di;
        unsigned int from = pos & (PAGE_CACHE_SIZE - 1);
        unsigned int to = from + len;
        int ret;
@@ -847,11 +847,10 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
                gfs2_page_add_databufs(ip, page, from, to);
 
        ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
-
-       if (likely(ret >= 0) && (inode->i_size > ip->i_disksize)) {
-               di = (struct gfs2_dinode *)dibh->b_data;
-               ip->i_disksize = inode->i_size;
-               di->di_size = cpu_to_be64(inode->i_size);
+       if (ret > 0) {
+               if (inode->i_size > ip->i_disksize)
+                       ip->i_disksize = inode->i_size;
+               gfs2_dinode_out(ip, dibh->b_data);
                mark_inode_dirty(inode);
        }
 
index 3a5d3f883e10137938c10ec106aceccb3f4b6153..329763530dc065847057b5be1c81b408763b46dd 100644 (file)
@@ -25,7 +25,6 @@
 #include "trans.h"
 #include "dir.h"
 #include "util.h"
-#include "ops_address.h"
 
 /* This doesn't need to be that large as max 64 bit pointers in a 4k
  * block is 512, so __u16 is fine for that. It saves stack space to
@@ -136,7 +135,9 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page)
                   and write it out to disk */
 
                unsigned int n = 1;
-               block = gfs2_alloc_block(ip, &n);
+               error = gfs2_alloc_block(ip, &block, &n);
+               if (error)
+                       goto out_brelse;
                if (isdir) {
                        gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), block, 1);
                        error = gfs2_dir_get_new_buffer(ip, block, &bh);
@@ -476,8 +477,11 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
        blks = dblks + iblks;
        i = sheight;
        do {
+               int error;
                n = blks - alloced;
-               bn = gfs2_alloc_block(ip, &n);
+               error = gfs2_alloc_block(ip, &bn, &n);
+               if (error)
+                       return error;
                alloced += n;
                if (state != ALLOC_DATA || gfs2_is_jdata(ip))
                        gfs2_trans_add_unrevoke(sdp, bn, n);
@@ -1008,7 +1012,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping)
                gfs2_trans_add_bh(ip->i_gl, bh, 0);
 
        zero_user(page, offset, length);
-
+       mark_buffer_dirty(bh);
 unlock:
        unlock_page(page);
        page_cache_release(page);
similarity index 100%
rename from fs/gfs2/ops_dentry.c
rename to fs/gfs2/dentry.c
index aef4d0c067488ccb942065aab8b0c292e8947213..297d7e5cebad8d283a9360ad86cf3a96a2028f02 100644 (file)
@@ -803,13 +803,20 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh,
 {
        struct gfs2_inode *ip = GFS2_I(inode);
        unsigned int n = 1;
-       u64 bn = gfs2_alloc_block(ip, &n);
-       struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn);
+       u64 bn;
+       int error;
+       struct buffer_head *bh;
        struct gfs2_leaf *leaf;
        struct gfs2_dirent *dent;
        struct qstr name = { .name = "", .len = 0, .hash = 0 };
+
+       error = gfs2_alloc_block(ip, &bn, &n);
+       if (error)
+               return NULL;
+       bh = gfs2_meta_new(ip->i_gl, bn);
        if (!bh)
                return NULL;
+
        gfs2_trans_add_unrevoke(GFS2_SB(inode), bn, 1);
        gfs2_trans_add_bh(ip->i_gl, bh, 1);
        gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF);
index 899763aed217498f827ed7743a4ad04c14f95b57..07ea9529adda162830829080dac6c5c98b382103 100644 (file)
@@ -582,8 +582,11 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp)
        struct gfs2_ea_header *ea;
        unsigned int n = 1;
        u64 block;
+       int error;
 
-       block = gfs2_alloc_block(ip, &n);
+       error = gfs2_alloc_block(ip, &block, &n);
+       if (error)
+               return error;
        gfs2_trans_add_unrevoke(sdp, block, 1);
        *bhp = gfs2_meta_new(ip->i_gl, block);
        gfs2_trans_add_bh(ip->i_gl, *bhp, 1);
@@ -617,6 +620,7 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
                    struct gfs2_ea_request *er)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       int error;
 
        ea->ea_data_len = cpu_to_be32(er->er_data_len);
        ea->ea_name_len = er->er_name_len;
@@ -642,7 +646,9 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
                        int mh_size = sizeof(struct gfs2_meta_header);
                        unsigned int n = 1;
 
-                       block = gfs2_alloc_block(ip, &n);
+                       error = gfs2_alloc_block(ip, &block, &n);
+                       if (error)
+                               return error;
                        gfs2_trans_add_unrevoke(sdp, block, 1);
                        bh = gfs2_meta_new(ip->i_gl, block);
                        gfs2_trans_add_bh(ip->i_gl, bh, 1);
@@ -963,7 +969,9 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er,
        } else {
                u64 blk;
                unsigned int n = 1;
-               blk = gfs2_alloc_block(ip, &n);
+               error = gfs2_alloc_block(ip, &blk, &n);
+               if (error)
+                       return error;
                gfs2_trans_add_unrevoke(sdp, blk, 1);
                indbh = gfs2_meta_new(ip->i_gl, blk);
                gfs2_trans_add_bh(ip->i_gl, indbh, 1);
similarity index 100%
rename from fs/gfs2/ops_export.c
rename to fs/gfs2/export.c
similarity index 97%
rename from fs/gfs2/ops_file.c
rename to fs/gfs2/file.c
index 5d82e91887e31e4eb139d9b34dd461aec66b63f1..73318a3ce6f1b1651f7fdaeb2ec985c45e7f76e0 100644 (file)
@@ -39,7 +39,6 @@
 #include "trans.h"
 #include "util.h"
 #include "eaops.h"
-#include "ops_address.h"
 
 /**
  * gfs2_llseek - seek to a location in a file
@@ -425,33 +424,36 @@ static struct vm_operations_struct gfs2_vm_ops = {
        .page_mkwrite = gfs2_page_mkwrite,
 };
 
-
 /**
  * gfs2_mmap -
  * @file: The file to map
  * @vma: The VMA which described the mapping
  *
- * Returns: 0 or error code
+ * There is no need to get a lock here unless we should be updating
+ * atime. We ignore any locking errors since the only consequence is
+ * a missed atime update (which will just be deferred until later).
+ *
+ * Returns: 0
  */
 
 static int gfs2_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
-       struct gfs2_holder i_gh;
-       int error;
 
-       gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
-       error = gfs2_glock_nq(&i_gh);
-       if (error) {
-               gfs2_holder_uninit(&i_gh);
-               return error;
-       }
+       if (!(file->f_flags & O_NOATIME)) {
+               struct gfs2_holder i_gh;
+               int error;
 
+               gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
+               error = gfs2_glock_nq(&i_gh);
+               file_accessed(file);
+               if (error == 0)
+                       gfs2_glock_dq_uninit(&i_gh);
+       }
        vma->vm_ops = &gfs2_vm_ops;
+       vma->vm_flags |= VM_CAN_NONLINEAR;
 
-       gfs2_glock_dq_uninit(&i_gh);
-
-       return error;
+       return 0;
 }
 
 /**
@@ -692,12 +694,10 @@ static void do_unflock(struct file *file, struct file_lock *fl)
 
 static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
 {
-       struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
-
        if (!(fl->fl_flags & FL_FLOCK))
                return -ENOLCK;
-       if (__mandatory_lock(&ip->i_inode))
-               return -ENOLCK;
+       if (fl->fl_type & LOCK_MAND)
+               return -EOPNOTSUPP;
 
        if (fl->fl_type == F_UNLCK) {
                do_unflock(file, fl);
index ff49810904897788465263af146bcb1ead719567..2bf62bcc5181729b44e7247d7ed8947805cd1263 100644 (file)
@@ -796,22 +796,37 @@ void gfs2_holder_uninit(struct gfs2_holder *gh)
        gh->gh_ip = 0;
 }
 
-static int just_schedule(void *word)
+/**
+ * gfs2_glock_holder_wait
+ * @word: unused
+ *
+ * This function and gfs2_glock_demote_wait both show up in the WCHAN
+ * field. Thus I've separated these otherwise identical functions in
+ * order to be more informative to the user.
+ */
+
+static int gfs2_glock_holder_wait(void *word)
 {
         schedule();
         return 0;
 }
 
+static int gfs2_glock_demote_wait(void *word)
+{
+       schedule();
+       return 0;
+}
+
 static void wait_on_holder(struct gfs2_holder *gh)
 {
        might_sleep();
-       wait_on_bit(&gh->gh_iflags, HIF_WAIT, just_schedule, TASK_UNINTERRUPTIBLE);
+       wait_on_bit(&gh->gh_iflags, HIF_WAIT, gfs2_glock_holder_wait, TASK_UNINTERRUPTIBLE);
 }
 
 static void wait_on_demote(struct gfs2_glock *gl)
 {
        might_sleep();
-       wait_on_bit(&gl->gl_flags, GLF_DEMOTE, just_schedule, TASK_UNINTERRUPTIBLE);
+       wait_on_bit(&gl->gl_flags, GLF_DEMOTE, gfs2_glock_demote_wait, TASK_UNINTERRUPTIBLE);
 }
 
 /**
index 70f87f43afa2b869559fa25bdb4fc90075d98468..d5e4ab155ca0a939c6219edb1137d442a9bf803d 100644 (file)
@@ -309,24 +309,6 @@ static void rgrp_go_unlock(struct gfs2_holder *gh)
        gfs2_rgrp_bh_put(gh->gh_gl->gl_object);
 }
 
-/**
- * rgrp_go_dump - print out an rgrp
- * @seq: The iterator
- * @gl: The glock in question
- *
- */
-
-static int rgrp_go_dump(struct seq_file *seq, const struct gfs2_glock *gl)
-{
-       const struct gfs2_rgrpd *rgd = gl->gl_object;
-       if (rgd == NULL)
-               return 0;
-       gfs2_print_dbg(seq, " R: n:%llu f:%02x b:%u/%u i:%u\n",
-                      (unsigned long long)rgd->rd_addr, rgd->rd_flags,
-                      rgd->rd_free, rgd->rd_free_clone, rgd->rd_dinodes);
-       return 0;
-}
-
 /**
  * trans_go_sync - promote/demote the transaction glock
  * @gl: the glock
@@ -410,7 +392,7 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = {
        .go_demote_ok = rgrp_go_demote_ok,
        .go_lock = rgrp_go_lock,
        .go_unlock = rgrp_go_unlock,
-       .go_dump = rgrp_go_dump,
+       .go_dump = gfs2_rgrp_dump,
        .go_type = LM_TYPE_RGRP,
        .go_min_hold_time = HZ / 5,
 };
index 399d1b97804972b3b6f4f27c801f6f2b823dbd0b..225347fbff3c25ee72fdaa1e3d5106356bafde16 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/fs.h>
 #include <linux/workqueue.h>
+#include <linux/slow-work.h>
 #include <linux/dlm.h>
 #include <linux/buffer_head.h>
 
@@ -63,9 +64,12 @@ struct gfs2_log_element {
        const struct gfs2_log_operations *le_ops;
 };
 
+#define GBF_FULL 1
+
 struct gfs2_bitmap {
        struct buffer_head *bi_bh;
        char *bi_clone;
+       unsigned long bi_flags;
        u32 bi_offset;
        u32 bi_start;
        u32 bi_len;
@@ -90,10 +94,11 @@ struct gfs2_rgrpd {
        struct gfs2_sbd *rd_sbd;
        unsigned int rd_bh_count;
        u32 rd_last_alloc;
-       unsigned char rd_flags;
-#define GFS2_RDF_CHECK        0x01      /* Need to check for unlinked inodes */
-#define GFS2_RDF_NOALLOC      0x02      /* rg prohibits allocation */
-#define GFS2_RDF_UPTODATE     0x04      /* rg is up to date */
+       u32 rd_flags;
+#define GFS2_RDF_CHECK         0x10000000 /* check for unlinked inodes */
+#define GFS2_RDF_UPTODATE      0x20000000 /* rg is up to date */
+#define GFS2_RDF_ERROR         0x40000000 /* error in rg */
+#define GFS2_RDF_MASK          0xf0000000 /* mask for internal flags */
 };
 
 enum gfs2_state_bits {
@@ -376,11 +381,11 @@ struct gfs2_journal_extent {
 struct gfs2_jdesc {
        struct list_head jd_list;
        struct list_head extent_list;
-
+       struct slow_work jd_work;
        struct inode *jd_inode;
+       unsigned long jd_flags;
+#define JDF_RECOVERY 1
        unsigned int jd_jid;
-       int jd_dirty;
-
        unsigned int jd_blocks;
 };
 
@@ -390,9 +395,6 @@ struct gfs2_statfs_change_host {
        s64 sc_dinodes;
 };
 
-#define GFS2_GLOCKD_DEFAULT    1
-#define GFS2_GLOCKD_MAX                16
-
 #define GFS2_QUOTA_DEFAULT     GFS2_QUOTA_OFF
 #define GFS2_QUOTA_OFF         0
 #define GFS2_QUOTA_ACCOUNT     1
@@ -418,6 +420,7 @@ struct gfs2_args {
        unsigned int ar_data:2;                 /* ordered/writeback */
        unsigned int ar_meta:1;                 /* mount metafs */
        unsigned int ar_discard:1;              /* discard requests */
+       int ar_commit;                          /* Commit interval */
 };
 
 struct gfs2_tune {
@@ -426,7 +429,6 @@ struct gfs2_tune {
        unsigned int gt_incore_log_blocks;
        unsigned int gt_log_flush_secs;
 
-       unsigned int gt_recoverd_secs;
        unsigned int gt_logd_secs;
 
        unsigned int gt_quota_simul_sync; /* Max quotavals to sync at once */
@@ -447,6 +449,7 @@ enum {
        SDF_JOURNAL_LIVE        = 1,
        SDF_SHUTDOWN            = 2,
        SDF_NOBARRIERS          = 3,
+       SDF_NORECOVERY          = 4,
 };
 
 #define GFS2_FSNAME_LEN                256
@@ -493,7 +496,6 @@ struct lm_lockstruct {
        unsigned long ls_flags;
        dlm_lockspace_t *ls_dlm;
 
-       int ls_recover_jid;
        int ls_recover_jid_done;
        int ls_recover_jid_status;
 };
@@ -582,7 +584,6 @@ struct gfs2_sbd {
 
        /* Daemon stuff */
 
-       struct task_struct *sd_recoverd_process;
        struct task_struct *sd_logd_process;
        struct task_struct *sd_quotad_process;
 
index 5a31d426116fbba09788f4c99be8a5e2e710b074..2f94bd723698a24723bbe1a84153f979169816ef 100644 (file)
@@ -30,7 +30,6 @@
 #include "inode.h"
 #include "log.h"
 #include "meta_io.h"
-#include "ops_address.h"
 #include "quota.h"
 #include "rgrp.h"
 #include "trans.h"
@@ -1047,154 +1046,7 @@ fail:
        return ERR_PTR(error);
 }
 
-/**
- * gfs2_rmdiri - Remove a directory
- * @dip: The parent directory of the directory to be removed
- * @name: The name of the directory to be removed
- * @ip: The GFS2 inode of the directory to be removed
- *
- * Assumes Glocks on dip and ip are held
- *
- * Returns: errno
- */
-
-int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
-               struct gfs2_inode *ip)
-{
-       struct qstr dotname;
-       int error;
-
-       if (ip->i_entries != 2) {
-               if (gfs2_consist_inode(ip))
-                       gfs2_dinode_print(ip);
-               return -EIO;
-       }
-
-       error = gfs2_dir_del(dip, name);
-       if (error)
-               return error;
-
-       error = gfs2_change_nlink(dip, -1);
-       if (error)
-               return error;
-
-       gfs2_str2qstr(&dotname, ".");
-       error = gfs2_dir_del(ip, &dotname);
-       if (error)
-               return error;
-
-       gfs2_str2qstr(&dotname, "..");
-       error = gfs2_dir_del(ip, &dotname);
-       if (error)
-               return error;
-
-       /* It looks odd, but it really should be done twice */
-       error = gfs2_change_nlink(ip, -1);
-       if (error)
-               return error;
-
-       error = gfs2_change_nlink(ip, -1);
-       if (error)
-               return error;
-
-       return error;
-}
-
-/*
- * gfs2_unlink_ok - check to see that a inode is still in a directory
- * @dip: the directory
- * @name: the name of the file
- * @ip: the inode
- *
- * Assumes that the lock on (at least) @dip is held.
- *
- * Returns: 0 if the parent/child relationship is correct, errno if it isn't
- */
-
-int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
-                  const struct gfs2_inode *ip)
-{
-       int error;
-
-       if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
-               return -EPERM;
-
-       if ((dip->i_inode.i_mode & S_ISVTX) &&
-           dip->i_inode.i_uid != current_fsuid() &&
-           ip->i_inode.i_uid != current_fsuid() && !capable(CAP_FOWNER))
-               return -EPERM;
-
-       if (IS_APPEND(&dip->i_inode))
-               return -EPERM;
-
-       error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC);
-       if (error)
-               return error;
-
-       error = gfs2_dir_check(&dip->i_inode, name, ip);
-       if (error)
-               return error;
-
-       return 0;
-}
-
-/**
- * gfs2_readlinki - return the contents of a symlink
- * @ip: the symlink's inode
- * @buf: a pointer to the buffer to be filled
- * @len: a pointer to the length of @buf
- *
- * If @buf is too small, a piece of memory is kmalloc()ed and needs
- * to be freed by the caller.
- *
- * Returns: errno
- */
-
-int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len)
-{
-       struct gfs2_holder i_gh;
-       struct buffer_head *dibh;
-       unsigned int x;
-       int error;
-
-       gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
-       error = gfs2_glock_nq(&i_gh);
-       if (error) {
-               gfs2_holder_uninit(&i_gh);
-               return error;
-       }
-
-       if (!ip->i_disksize) {
-               gfs2_consist_inode(ip);
-               error = -EIO;
-               goto out;
-       }
-
-       error = gfs2_meta_inode_buffer(ip, &dibh);
-       if (error)
-               goto out;
-
-       x = ip->i_disksize + 1;
-       if (x > *len) {
-               *buf = kmalloc(x, GFP_NOFS);
-               if (!*buf) {
-                       error = -ENOMEM;
-                       goto out_brelse;
-               }
-       }
-
-       memcpy(*buf, dibh->b_data + sizeof(struct gfs2_dinode), x);
-       *len = x;
-
-out_brelse:
-       brelse(dibh);
-out:
-       gfs2_glock_dq_uninit(&i_gh);
-       return error;
-}
-
-static int
-__gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
+static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
 {
        struct buffer_head *dibh;
        int error;
index c30be2b66580f9740cfa07f65abc1b45c2ad8181..c341aaf67adb24c7623e7e458b87afeaf846106e 100644 (file)
 #define __INODE_DOT_H__
 
 #include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/mm.h>
 #include "util.h"
 
+extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask);
+extern int gfs2_internal_read(struct gfs2_inode *ip,
+                             struct file_ra_state *ra_state,
+                             char *buf, loff_t *pos, unsigned size);
+extern void gfs2_set_aops(struct inode *inode);
+
 static inline int gfs2_is_stuffed(const struct gfs2_inode *ip)
 {
        return !ip->i_height;
@@ -73,30 +81,26 @@ static inline void gfs2_inum_out(const struct gfs2_inode *ip,
 }
 
 
-void gfs2_set_iop(struct inode *inode);
-struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, 
-                               u64 no_addr, u64 no_formal_ino,
-                               int skip_freeing);
-struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr);
-
-int gfs2_inode_refresh(struct gfs2_inode *ip);
-
-int gfs2_dinode_dealloc(struct gfs2_inode *inode);
-int gfs2_change_nlink(struct gfs2_inode *ip, int diff);
-struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
-                          int is_root);
-struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
-                          unsigned int mode, dev_t dev);
-int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
-               struct gfs2_inode *ip);
-int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
-                  const struct gfs2_inode *ip);
-int gfs2_permission(struct inode *inode, int mask);
-int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len);
-int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr);
-struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
-void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf);
-void gfs2_dinode_print(const struct gfs2_inode *ip);
+extern void gfs2_set_iop(struct inode *inode);
+extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, 
+                                      u64 no_addr, u64 no_formal_ino,
+                                      int skip_freeing);
+extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr);
+
+extern int gfs2_inode_refresh(struct gfs2_inode *ip);
+
+extern int gfs2_dinode_dealloc(struct gfs2_inode *inode);
+extern int gfs2_change_nlink(struct gfs2_inode *ip, int diff);
+extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
+                                 int is_root);
+extern struct inode *gfs2_createi(struct gfs2_holder *ghs,
+                                 const struct qstr *name,
+                                 unsigned int mode, dev_t dev);
+extern int gfs2_permission(struct inode *inode, int mask);
+extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr);
+extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
+extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf);
+extern void gfs2_dinode_print(const struct gfs2_inode *ip);
 
 extern const struct inode_operations gfs2_file_iops;
 extern const struct inode_operations gfs2_dir_iops;
index 98918a756410ca576f3fec0ba49fa8a82869033f..aa62cf5976e80be8efc3c520fee9919072d98f1f 100644 (file)
@@ -120,7 +120,7 @@ __acquires(&sdp->sd_log_lock)
                        lock_buffer(bh);
                        if (test_clear_buffer_dirty(bh)) {
                                bh->b_end_io = end_buffer_write_sync;
-                               submit_bh(WRITE, bh);
+                               submit_bh(WRITE_SYNC_PLUG, bh);
                        } else {
                                unlock_buffer(bh);
                                brelse(bh);
@@ -604,7 +604,7 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
        if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags))
                goto skip_barrier;
        get_bh(bh);
-       submit_bh(WRITE_BARRIER | (1 << BIO_RW_META), bh);
+       submit_bh(WRITE_SYNC | (1 << BIO_RW_BARRIER) | (1 << BIO_RW_META), bh);
        wait_on_buffer(bh);
        if (buffer_eopnotsupp(bh)) {
                clear_buffer_eopnotsupp(bh);
@@ -664,7 +664,7 @@ static void gfs2_ordered_write(struct gfs2_sbd *sdp)
                lock_buffer(bh);
                if (buffer_mapped(bh) && test_clear_buffer_dirty(bh)) {
                        bh->b_end_io = end_buffer_write_sync;
-                       submit_bh(WRITE, bh);
+                       submit_bh(WRITE_SYNC_PLUG, bh);
                } else {
                        unlock_buffer(bh);
                        brelse(bh);
index 80e4f5f898bb5170c2168d42975ba1604f30157a..00315f50fa467daa94214c8e37e877eb76eaf00c 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/completion.h>
 #include <linux/buffer_head.h>
 #include <linux/gfs2_ondisk.h>
+#include <linux/bio.h>
+#include <linux/fs.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -189,7 +191,7 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp)
                }
 
                gfs2_log_unlock(sdp);
-               submit_bh(WRITE, bh);
+               submit_bh(WRITE_SYNC_PLUG, bh);
                gfs2_log_lock(sdp);
 
                n = 0;
@@ -199,7 +201,7 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp)
                        gfs2_log_unlock(sdp);
                        lock_buffer(bd2->bd_bh);
                        bh = gfs2_log_fake_buf(sdp, bd2->bd_bh);
-                       submit_bh(WRITE, bh);
+                       submit_bh(WRITE_SYNC_PLUG, bh);
                        gfs2_log_lock(sdp);
                        if (++n >= num)
                                break;
@@ -341,7 +343,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
                sdp->sd_log_num_revoke--;
 
                if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) {
-                       submit_bh(WRITE, bh);
+                       submit_bh(WRITE_SYNC_PLUG, bh);
 
                        bh = gfs2_log_get_buf(sdp);
                        mh = (struct gfs2_meta_header *)bh->b_data;
@@ -358,7 +360,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
        }
        gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
 
-       submit_bh(WRITE, bh);
+       submit_bh(WRITE_SYNC_PLUG, bh);
 }
 
 static void revoke_lo_before_scan(struct gfs2_jdesc *jd,
@@ -560,7 +562,7 @@ static void gfs2_write_blocks(struct gfs2_sbd *sdp, struct buffer_head *bh,
        ptr = bh_log_ptr(bh);
        
        get_bh(bh);
-       submit_bh(WRITE, bh);
+       submit_bh(WRITE_SYNC_PLUG, bh);
        gfs2_log_lock(sdp);
        while(!list_empty(list)) {
                bd = list_entry(list->next, struct gfs2_bufdata, bd_le.le_list);
@@ -586,7 +588,7 @@ static void gfs2_write_blocks(struct gfs2_sbd *sdp, struct buffer_head *bh,
                } else {
                        bh1 = gfs2_log_fake_buf(sdp, bd->bd_bh);
                }
-               submit_bh(WRITE, bh1);
+               submit_bh(WRITE_SYNC_PLUG, bh1);
                gfs2_log_lock(sdp);
                ptr += 2;
        }
index a6892ed0840a33715c6143ef67cb95e1dbbae874..eacd78a5d0827c3e0d7c37fb89eace335b400eca 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/gfs2_ondisk.h>
 #include <asm/atomic.h>
+#include <linux/slow-work.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -113,12 +114,18 @@ static int __init init_gfs2_fs(void)
        if (error)
                goto fail_unregister;
 
+       error = slow_work_register_user();
+       if (error)
+               goto fail_slow;
+
        gfs2_register_debugfs();
 
        printk("GFS2 (built %s %s) installed\n", __DATE__, __TIME__);
 
        return 0;
 
+fail_slow:
+       unregister_filesystem(&gfs2meta_fs_type);
 fail_unregister:
        unregister_filesystem(&gfs2_fs_type);
 fail:
@@ -156,6 +163,7 @@ static void __exit exit_gfs2_fs(void)
        gfs2_unregister_debugfs();
        unregister_filesystem(&gfs2_fs_type);
        unregister_filesystem(&gfs2meta_fs_type);
+       slow_work_unregister_user();
 
        kmem_cache_destroy(gfs2_quotad_cachep);
        kmem_cache_destroy(gfs2_rgrpd_cachep);
index 8d6f13256b2634c520543d7b7acb615c0c397d96..cb8d7a93d5ec257204c93aac033c95146fdd1a07 100644 (file)
 #include "rgrp.h"
 #include "trans.h"
 #include "util.h"
-#include "ops_address.h"
 
-static int aspace_get_block(struct inode *inode, sector_t lblock,
-                           struct buffer_head *bh_result, int create)
+static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wbc)
 {
-       gfs2_assert_warn(inode->i_sb->s_fs_info, 0);
-       return -EOPNOTSUPP;
-}
+       int err;
+       struct buffer_head *bh, *head;
+       int nr_underway = 0;
+       int write_op = (1 << BIO_RW_META) | ((wbc->sync_mode == WB_SYNC_ALL ?
+                       WRITE_SYNC_PLUG : WRITE));
+
+       BUG_ON(!PageLocked(page));
+       BUG_ON(!page_has_buffers(page));
+
+       head = page_buffers(page);
+       bh = head;
+
+       do {
+               if (!buffer_mapped(bh))
+                       continue;
+               /*
+                * If it's a fully non-blocking write attempt and we cannot
+                * lock the buffer then redirty the page.  Note that this can
+                * potentially cause a busy-wait loop from pdflush and kswapd
+                * activity, but those code paths have their own higher-level
+                * throttling.
+                */
+               if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) {
+                       lock_buffer(bh);
+               } else if (!trylock_buffer(bh)) {
+                       redirty_page_for_writepage(wbc, page);
+                       continue;
+               }
+               if (test_clear_buffer_dirty(bh)) {
+                       mark_buffer_async_write(bh);
+               } else {
+                       unlock_buffer(bh);
+               }
+       } while ((bh = bh->b_this_page) != head);
+
+       /*
+        * The page and its buffers are protected by PageWriteback(), so we can
+        * drop the bh refcounts early.
+        */
+       BUG_ON(PageWriteback(page));
+       set_page_writeback(page);
+
+       do {
+               struct buffer_head *next = bh->b_this_page;
+               if (buffer_async_write(bh)) {
+                       submit_bh(write_op, bh);
+                       nr_underway++;
+               }
+               bh = next;
+       } while (bh != head);
+       unlock_page(page);
 
-static int gfs2_aspace_writepage(struct page *page,
-                                struct writeback_control *wbc)
-{
-       return block_write_full_page(page, aspace_get_block, wbc);
+       err = 0;
+       if (nr_underway == 0)
+               end_page_writeback(page);
+
+       return err;
 }
 
 static const struct address_space_operations aspace_aops = {
@@ -201,16 +248,32 @@ struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno)
 int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
                   struct buffer_head **bhp)
 {
-       *bhp = gfs2_getbuf(gl, blkno, CREATE);
-       if (!buffer_uptodate(*bhp)) {
-               ll_rw_block(READ_META, 1, bhp);
-               if (flags & DIO_WAIT) {
-                       int error = gfs2_meta_wait(gl->gl_sbd, *bhp);
-                       if (error) {
-                               brelse(*bhp);
-                               return error;
-                       }
-               }
+       struct gfs2_sbd *sdp = gl->gl_sbd;
+       struct buffer_head *bh;
+
+       if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+               return -EIO;
+
+       *bhp = bh = gfs2_getbuf(gl, blkno, CREATE);
+
+       lock_buffer(bh);
+       if (buffer_uptodate(bh)) {
+               unlock_buffer(bh);
+               return 0;
+       }
+       bh->b_end_io = end_buffer_read_sync;
+       get_bh(bh);
+       submit_bh(READ_SYNC | (1 << BIO_RW_META), bh);
+       if (!(flags & DIO_WAIT))
+               return 0;
+
+       wait_on_buffer(bh);
+       if (unlikely(!buffer_uptodate(bh))) {
+               struct gfs2_trans *tr = current->journal_info;
+               if (tr && tr->tr_touched)
+                       gfs2_io_error_bh(sdp, bh);
+               brelse(bh);
+               return -EIO;
        }
 
        return 0;
@@ -404,7 +467,7 @@ struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen)
        if (buffer_uptodate(first_bh))
                goto out;
        if (!buffer_locked(first_bh))
-               ll_rw_block(READ_META, 1, &first_bh);
+               ll_rw_block(READ_SYNC | (1 << BIO_RW_META), 1, &first_bh);
 
        dblock++;
        extlen--;
diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c
deleted file mode 100644 (file)
index f7e8527..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/completion.h>
-#include <linux/buffer_head.h>
-#include <linux/gfs2_ondisk.h>
-#include <linux/parser.h>
-
-#include "gfs2.h"
-#include "incore.h"
-#include "super.h"
-#include "sys.h"
-#include "util.h"
-
-enum {
-       Opt_lockproto,
-       Opt_locktable,
-       Opt_hostdata,
-       Opt_spectator,
-       Opt_ignore_local_fs,
-       Opt_localflocks,
-       Opt_localcaching,
-       Opt_debug,
-       Opt_nodebug,
-       Opt_upgrade,
-       Opt_acl,
-       Opt_noacl,
-       Opt_quota_off,
-       Opt_quota_account,
-       Opt_quota_on,
-       Opt_quota,
-       Opt_noquota,
-       Opt_suiddir,
-       Opt_nosuiddir,
-       Opt_data_writeback,
-       Opt_data_ordered,
-       Opt_meta,
-       Opt_discard,
-       Opt_nodiscard,
-       Opt_err,
-};
-
-static const match_table_t tokens = {
-       {Opt_lockproto, "lockproto=%s"},
-       {Opt_locktable, "locktable=%s"},
-       {Opt_hostdata, "hostdata=%s"},
-       {Opt_spectator, "spectator"},
-       {Opt_ignore_local_fs, "ignore_local_fs"},
-       {Opt_localflocks, "localflocks"},
-       {Opt_localcaching, "localcaching"},
-       {Opt_debug, "debug"},
-       {Opt_nodebug, "nodebug"},
-       {Opt_upgrade, "upgrade"},
-       {Opt_acl, "acl"},
-       {Opt_noacl, "noacl"},
-       {Opt_quota_off, "quota=off"},
-       {Opt_quota_account, "quota=account"},
-       {Opt_quota_on, "quota=on"},
-       {Opt_quota, "quota"},
-       {Opt_noquota, "noquota"},
-       {Opt_suiddir, "suiddir"},
-       {Opt_nosuiddir, "nosuiddir"},
-       {Opt_data_writeback, "data=writeback"},
-       {Opt_data_ordered, "data=ordered"},
-       {Opt_meta, "meta"},
-       {Opt_discard, "discard"},
-       {Opt_nodiscard, "nodiscard"},
-       {Opt_err, NULL}
-};
-
-/**
- * gfs2_mount_args - Parse mount options
- * @sdp:
- * @data:
- *
- * Return: errno
- */
-
-int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
-{
-       char *o;
-       int token;
-       substring_t tmp[MAX_OPT_ARGS];
-
-       /* Split the options into tokens with the "," character and
-          process them */
-
-       while (1) {
-               o = strsep(&options, ",");
-               if (o == NULL)
-                       break;
-               if (*o == '\0')
-                       continue;
-
-               token = match_token(o, tokens, tmp);
-               switch (token) {
-               case Opt_lockproto:
-                       match_strlcpy(args->ar_lockproto, &tmp[0],
-                                     GFS2_LOCKNAME_LEN);
-                       break;
-               case Opt_locktable:
-                       match_strlcpy(args->ar_locktable, &tmp[0],
-                                     GFS2_LOCKNAME_LEN);
-                       break;
-               case Opt_hostdata:
-                       match_strlcpy(args->ar_hostdata, &tmp[0],
-                                     GFS2_LOCKNAME_LEN);
-                       break;
-               case Opt_spectator:
-                       args->ar_spectator = 1;
-                       break;
-               case Opt_ignore_local_fs:
-                       args->ar_ignore_local_fs = 1;
-                       break;
-               case Opt_localflocks:
-                       args->ar_localflocks = 1;
-                       break;
-               case Opt_localcaching:
-                       args->ar_localcaching = 1;
-                       break;
-               case Opt_debug:
-                       args->ar_debug = 1;
-                       break;
-               case Opt_nodebug:
-                       args->ar_debug = 0;
-                       break;
-               case Opt_upgrade:
-                       args->ar_upgrade = 1;
-                       break;
-               case Opt_acl:
-                       args->ar_posix_acl = 1;
-                       break;
-               case Opt_noacl:
-                       args->ar_posix_acl = 0;
-                       break;
-               case Opt_quota_off:
-               case Opt_noquota:
-                       args->ar_quota = GFS2_QUOTA_OFF;
-                       break;
-               case Opt_quota_account:
-                       args->ar_quota = GFS2_QUOTA_ACCOUNT;
-                       break;
-               case Opt_quota_on:
-               case Opt_quota:
-                       args->ar_quota = GFS2_QUOTA_ON;
-                       break;
-               case Opt_suiddir:
-                       args->ar_suiddir = 1;
-                       break;
-               case Opt_nosuiddir:
-                       args->ar_suiddir = 0;
-                       break;
-               case Opt_data_writeback:
-                       args->ar_data = GFS2_DATA_WRITEBACK;
-                       break;
-               case Opt_data_ordered:
-                       args->ar_data = GFS2_DATA_ORDERED;
-                       break;
-               case Opt_meta:
-                       args->ar_meta = 1;
-                       break;
-               case Opt_discard:
-                       args->ar_discard = 1;
-                       break;
-               case Opt_nodiscard:
-                       args->ar_discard = 0;
-                       break;
-               case Opt_err:
-               default:
-                       fs_info(sdp, "invalid mount option: %s\n", o);
-                       return -EINVAL;
-               }
-       }
-
-       return 0;
-}
-
diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h
deleted file mode 100644 (file)
index 5da2128..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#ifndef __OPS_ADDRESS_DOT_H__
-#define __OPS_ADDRESS_DOT_H__
-
-#include <linux/fs.h>
-#include <linux/buffer_head.h>
-#include <linux/mm.h>
-
-extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask);
-extern int gfs2_internal_read(struct gfs2_inode *ip,
-                             struct file_ra_state *ra_state,
-                             char *buf, loff_t *pos, unsigned size);
-extern void gfs2_set_aops(struct inode *inode);
-
-#endif /* __OPS_ADDRESS_DOT_H__ */
index 1ff9473ea7531999436b20d618ce142853abef3e..cc34f271b3e7f470230efe58bbeeed3cf6682424 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/gfs2_ondisk.h>
+#include <linux/slow-work.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -55,8 +56,6 @@ static void gfs2_tune_init(struct gfs2_tune *gt)
        spin_lock_init(&gt->gt_spin);
 
        gt->gt_incore_log_blocks = 1024;
-       gt->gt_log_flush_secs = 60;
-       gt->gt_recoverd_secs = 60;
        gt->gt_logd_secs = 1;
        gt->gt_quota_simul_sync = 64;
        gt->gt_quota_warn_period = 10;
@@ -526,11 +525,11 @@ static int init_sb(struct gfs2_sbd *sdp, int silent)
        }
 
        /* Set up the buffer cache and SB for real */
-       if (sdp->sd_sb.sb_bsize < bdev_hardsect_size(sb->s_bdev)) {
+       if (sdp->sd_sb.sb_bsize < bdev_logical_block_size(sb->s_bdev)) {
                ret = -EINVAL;
                fs_err(sdp, "FS block size (%u) is too small for device "
                       "block size (%u)\n",
-                      sdp->sd_sb.sb_bsize, bdev_hardsect_size(sb->s_bdev));
+                      sdp->sd_sb.sb_bsize, bdev_logical_block_size(sb->s_bdev));
                goto out;
        }
        if (sdp->sd_sb.sb_bsize > PAGE_SIZE) {
@@ -676,6 +675,7 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
                        break;
 
                INIT_LIST_HEAD(&jd->extent_list);
+               slow_work_init(&jd->jd_work, &gfs2_recover_ops);
                jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1);
                if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
                        if (!jd->jd_inode)
@@ -701,14 +701,13 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
 {
        struct inode *master = sdp->sd_master_dir->d_inode;
        struct gfs2_holder ji_gh;
-       struct task_struct *p;
        struct gfs2_inode *ip;
        int jindex = 1;
        int error = 0;
 
        if (undo) {
                jindex = 0;
-               goto fail_recoverd;
+               goto fail_jinode_gh;
        }
 
        sdp->sd_jindex = gfs2_lookup_simple(master, "jindex");
@@ -801,18 +800,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
        gfs2_glock_dq_uninit(&ji_gh);
        jindex = 0;
 
-       p = kthread_run(gfs2_recoverd, sdp, "gfs2_recoverd");
-       error = IS_ERR(p);
-       if (error) {
-               fs_err(sdp, "can't start recoverd thread: %d\n", error);
-               goto fail_jinode_gh;
-       }
-       sdp->sd_recoverd_process = p;
-
        return 0;
 
-fail_recoverd:
-       kthread_stop(sdp->sd_recoverd_process);
 fail_jinode_gh:
        if (!sdp->sd_args.ar_spectator)
                gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
@@ -1165,6 +1154,7 @@ static int fill_super(struct super_block *sb, void *data, int silent)
 
        sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT;
        sdp->sd_args.ar_data = GFS2_DATA_DEFAULT;
+       sdp->sd_args.ar_commit = 60;
 
        error = gfs2_mount_args(sdp, &sdp->sd_args, data);
        if (error) {
@@ -1172,8 +1162,10 @@ static int fill_super(struct super_block *sb, void *data, int silent)
                goto fail;
        }
 
-       if (sdp->sd_args.ar_spectator)
+       if (sdp->sd_args.ar_spectator) {
                 sb->s_flags |= MS_RDONLY;
+               set_bit(SDF_NORECOVERY, &sdp->sd_flags);
+       }
        if (sdp->sd_args.ar_posix_acl)
                sb->s_flags |= MS_POSIXACL;
 
@@ -1191,6 +1183,8 @@ static int fill_super(struct super_block *sb, void *data, int silent)
                                GFS2_BASIC_BLOCK_SHIFT;
        sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift;
 
+       sdp->sd_tune.gt_log_flush_secs = sdp->sd_args.ar_commit;
+
        error = init_names(sdp, silent);
        if (error)
                goto fail;
@@ -1279,9 +1273,22 @@ static int gfs2_get_sb(struct file_system_type *fs_type, int flags,
        return get_sb_bdev(fs_type, flags, dev_name, data, fill_super, mnt);
 }
 
-static struct super_block *get_gfs2_sb(const char *dev_name)
+static int test_meta_super(struct super_block *s, void *ptr)
+{
+       struct block_device *bdev = ptr;
+       return (bdev == s->s_bdev);
+}
+
+static int set_meta_super(struct super_block *s, void *ptr)
 {
-       struct super_block *sb;
+       return -EINVAL;
+}
+
+static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags,
+                           const char *dev_name, void *data, struct vfsmount *mnt)
+{
+       struct super_block *s;
+       struct gfs2_sbd *sdp;
        struct path path;
        int error;
 
@@ -1289,30 +1296,17 @@ static struct super_block *get_gfs2_sb(const char *dev_name)
        if (error) {
                printk(KERN_WARNING "GFS2: path_lookup on %s returned error %d\n",
                       dev_name, error);
-               return NULL;
+               return error;
        }
-       sb = path.dentry->d_inode->i_sb;
-       if (sb && (sb->s_type == &gfs2_fs_type))
-               atomic_inc(&sb->s_active);
-       else
-               sb = NULL;
+       s = sget(&gfs2_fs_type, test_meta_super, set_meta_super,
+                path.dentry->d_inode->i_sb->s_bdev);
        path_put(&path);
-       return sb;
-}
-
-static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags,
-                           const char *dev_name, void *data, struct vfsmount *mnt)
-{
-       struct super_block *sb = NULL;
-       struct gfs2_sbd *sdp;
-
-       sb = get_gfs2_sb(dev_name);
-       if (!sb) {
+       if (IS_ERR(s)) {
                printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n");
-               return -ENOENT;
+               return PTR_ERR(s);
        }
-       sdp = sb->s_fs_info;
-       mnt->mnt_sb = sb;
+       sdp = s->s_fs_info;
+       mnt->mnt_sb = s;
        mnt->mnt_root = dget(sdp->sd_master_dir);
        return 0;
 }
index 1c70fa5168d6aa46ddf872f326a2a1399bee981a..f8bd20baf99c4ab6d78d2141c50d3368e99228b9 100644 (file)
@@ -262,6 +262,44 @@ out_parent:
        return error;
 }
 
+/*
+ * gfs2_unlink_ok - check to see that a inode is still in a directory
+ * @dip: the directory
+ * @name: the name of the file
+ * @ip: the inode
+ *
+ * Assumes that the lock on (at least) @dip is held.
+ *
+ * Returns: 0 if the parent/child relationship is correct, errno if it isn't
+ */
+
+static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
+                         const struct gfs2_inode *ip)
+{
+       int error;
+
+       if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
+               return -EPERM;
+
+       if ((dip->i_inode.i_mode & S_ISVTX) &&
+           dip->i_inode.i_uid != current_fsuid() &&
+           ip->i_inode.i_uid != current_fsuid() && !capable(CAP_FOWNER))
+               return -EPERM;
+
+       if (IS_APPEND(&dip->i_inode))
+               return -EPERM;
+
+       error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC);
+       if (error)
+               return error;
+
+       error = gfs2_dir_check(&dip->i_inode, name, ip);
+       if (error)
+               return error;
+
+       return 0;
+}
+
 /**
  * gfs2_unlink - Unlink a file
  * @dir: The inode of the directory containing the file to unlink
@@ -472,6 +510,59 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        return 0;
 }
 
+/**
+ * gfs2_rmdiri - Remove a directory
+ * @dip: The parent directory of the directory to be removed
+ * @name: The name of the directory to be removed
+ * @ip: The GFS2 inode of the directory to be removed
+ *
+ * Assumes Glocks on dip and ip are held
+ *
+ * Returns: errno
+ */
+
+static int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
+                      struct gfs2_inode *ip)
+{
+       struct qstr dotname;
+       int error;
+
+       if (ip->i_entries != 2) {
+               if (gfs2_consist_inode(ip))
+                       gfs2_dinode_print(ip);
+               return -EIO;
+       }
+
+       error = gfs2_dir_del(dip, name);
+       if (error)
+               return error;
+
+       error = gfs2_change_nlink(dip, -1);
+       if (error)
+               return error;
+
+       gfs2_str2qstr(&dotname, ".");
+       error = gfs2_dir_del(ip, &dotname);
+       if (error)
+               return error;
+
+       gfs2_str2qstr(&dotname, "..");
+       error = gfs2_dir_del(ip, &dotname);
+       if (error)
+               return error;
+
+       /* It looks odd, but it really should be done twice */
+       error = gfs2_change_nlink(ip, -1);
+       if (error)
+               return error;
+
+       error = gfs2_change_nlink(ip, -1);
+       if (error)
+               return error;
+
+       return error;
+}
+
 /**
  * gfs2_rmdir - Remove a directory
  * @dir: The parent directory of the directory to be removed
@@ -884,6 +975,61 @@ out:
        return error;
 }
 
+/**
+ * gfs2_readlinki - return the contents of a symlink
+ * @ip: the symlink's inode
+ * @buf: a pointer to the buffer to be filled
+ * @len: a pointer to the length of @buf
+ *
+ * If @buf is too small, a piece of memory is kmalloc()ed and needs
+ * to be freed by the caller.
+ *
+ * Returns: errno
+ */
+
+static int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len)
+{
+       struct gfs2_holder i_gh;
+       struct buffer_head *dibh;
+       unsigned int x;
+       int error;
+
+       gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
+       error = gfs2_glock_nq(&i_gh);
+       if (error) {
+               gfs2_holder_uninit(&i_gh);
+               return error;
+       }
+
+       if (!ip->i_disksize) {
+               gfs2_consist_inode(ip);
+               error = -EIO;
+               goto out;
+       }
+
+       error = gfs2_meta_inode_buffer(ip, &dibh);
+       if (error)
+               goto out;
+
+       x = ip->i_disksize + 1;
+       if (x > *len) {
+               *buf = kmalloc(x, GFP_NOFS);
+               if (!*buf) {
+                       error = -ENOMEM;
+                       goto out_brelse;
+               }
+       }
+
+       memcpy(*buf, dibh->b_data + sizeof(struct gfs2_dinode), x);
+       *len = x;
+
+out_brelse:
+       brelse(dibh);
+out:
+       gfs2_glock_dq_uninit(&i_gh);
+       return error;
+}
+
 /**
  * gfs2_readlink - Read the value of a symlink
  * @dentry: the symlink
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
deleted file mode 100644 (file)
index 4580195..0000000
+++ /dev/null
@@ -1,723 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2008 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/completion.h>
-#include <linux/buffer_head.h>
-#include <linux/statfs.h>
-#include <linux/seq_file.h>
-#include <linux/mount.h>
-#include <linux/kthread.h>
-#include <linux/delay.h>
-#include <linux/gfs2_ondisk.h>
-#include <linux/crc32.h>
-#include <linux/time.h>
-
-#include "gfs2.h"
-#include "incore.h"
-#include "glock.h"
-#include "inode.h"
-#include "log.h"
-#include "quota.h"
-#include "recovery.h"
-#include "rgrp.h"
-#include "super.h"
-#include "sys.h"
-#include "util.h"
-#include "trans.h"
-#include "dir.h"
-#include "eattr.h"
-#include "bmap.h"
-#include "meta_io.h"
-
-#define args_neq(a1, a2, x) ((a1)->ar_##x != (a2)->ar_##x)
-
-/**
- * gfs2_write_inode - Make sure the inode is stable on the disk
- * @inode: The inode
- * @sync: synchronous write flag
- *
- * Returns: errno
- */
-
-static int gfs2_write_inode(struct inode *inode, int sync)
-{
-       struct gfs2_inode *ip = GFS2_I(inode);
-       struct gfs2_sbd *sdp = GFS2_SB(inode);
-       struct gfs2_holder gh;
-       struct buffer_head *bh;
-       struct timespec atime;
-       struct gfs2_dinode *di;
-       int ret = 0;
-
-       /* Check this is a "normal" inode, etc */
-       if (!test_bit(GIF_USER, &ip->i_flags) ||
-           (current->flags & PF_MEMALLOC))
-               return 0;
-       ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
-       if (ret)
-               goto do_flush;
-       ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
-       if (ret)
-               goto do_unlock;
-       ret = gfs2_meta_inode_buffer(ip, &bh);
-       if (ret == 0) {
-               di = (struct gfs2_dinode *)bh->b_data;
-               atime.tv_sec = be64_to_cpu(di->di_atime);
-               atime.tv_nsec = be32_to_cpu(di->di_atime_nsec);
-               if (timespec_compare(&inode->i_atime, &atime) > 0) {
-                       gfs2_trans_add_bh(ip->i_gl, bh, 1);
-                       gfs2_dinode_out(ip, bh->b_data);
-               }
-               brelse(bh);
-       }
-       gfs2_trans_end(sdp);
-do_unlock:
-       gfs2_glock_dq_uninit(&gh);
-do_flush:
-       if (sync != 0)
-               gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
-       return ret;
-}
-
-/**
- * gfs2_make_fs_ro - Turn a Read-Write FS into a Read-Only one
- * @sdp: the filesystem
- *
- * Returns: errno
- */
-
-static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
-{
-       struct gfs2_holder t_gh;
-       int error;
-
-       gfs2_quota_sync(sdp);
-       gfs2_statfs_sync(sdp);
-
-       error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE,
-                                  &t_gh);
-       if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
-               return error;
-
-       gfs2_meta_syncfs(sdp);
-       gfs2_log_shutdown(sdp);
-
-       clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
-
-       if (t_gh.gh_gl)
-               gfs2_glock_dq_uninit(&t_gh);
-
-       gfs2_quota_cleanup(sdp);
-
-       return error;
-}
-
-/**
- * gfs2_put_super - Unmount the filesystem
- * @sb: The VFS superblock
- *
- */
-
-static void gfs2_put_super(struct super_block *sb)
-{
-       struct gfs2_sbd *sdp = sb->s_fs_info;
-       int error;
-
-       /*  Unfreeze the filesystem, if we need to  */
-
-       mutex_lock(&sdp->sd_freeze_lock);
-       if (sdp->sd_freeze_count)
-               gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
-       mutex_unlock(&sdp->sd_freeze_lock);
-
-       kthread_stop(sdp->sd_quotad_process);
-       kthread_stop(sdp->sd_logd_process);
-       kthread_stop(sdp->sd_recoverd_process);
-
-       if (!(sb->s_flags & MS_RDONLY)) {
-               error = gfs2_make_fs_ro(sdp);
-               if (error)
-                       gfs2_io_error(sdp);
-       }
-       /*  At this point, we're through modifying the disk  */
-
-       /*  Release stuff  */
-
-       iput(sdp->sd_jindex);
-       iput(sdp->sd_inum_inode);
-       iput(sdp->sd_statfs_inode);
-       iput(sdp->sd_rindex);
-       iput(sdp->sd_quota_inode);
-
-       gfs2_glock_put(sdp->sd_rename_gl);
-       gfs2_glock_put(sdp->sd_trans_gl);
-
-       if (!sdp->sd_args.ar_spectator) {
-               gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
-               gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
-               gfs2_glock_dq_uninit(&sdp->sd_ir_gh);
-               gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
-               gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
-               iput(sdp->sd_ir_inode);
-               iput(sdp->sd_sc_inode);
-               iput(sdp->sd_qc_inode);
-       }
-
-       gfs2_glock_dq_uninit(&sdp->sd_live_gh);
-       gfs2_clear_rgrpd(sdp);
-       gfs2_jindex_free(sdp);
-       /*  Take apart glock structures and buffer lists  */
-       gfs2_gl_hash_clear(sdp);
-       /*  Unmount the locking protocol  */
-       gfs2_lm_unmount(sdp);
-
-       /*  At this point, we're through participating in the lockspace  */
-       gfs2_sys_fs_del(sdp);
-}
-
-/**
- * gfs2_write_super
- * @sb: the superblock
- *
- */
-
-static void gfs2_write_super(struct super_block *sb)
-{
-       sb->s_dirt = 0;
-}
-
-/**
- * gfs2_sync_fs - sync the filesystem
- * @sb: the superblock
- *
- * Flushes the log to disk.
- */
-
-static int gfs2_sync_fs(struct super_block *sb, int wait)
-{
-       sb->s_dirt = 0;
-       if (wait && sb->s_fs_info)
-               gfs2_log_flush(sb->s_fs_info, NULL);
-       return 0;
-}
-
-/**
- * gfs2_freeze - prevent further writes to the filesystem
- * @sb: the VFS structure for the filesystem
- *
- */
-
-static int gfs2_freeze(struct super_block *sb)
-{
-       struct gfs2_sbd *sdp = sb->s_fs_info;
-       int error;
-
-       if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
-               return -EINVAL;
-
-       for (;;) {
-               error = gfs2_freeze_fs(sdp);
-               if (!error)
-                       break;
-
-               switch (error) {
-               case -EBUSY:
-                       fs_err(sdp, "waiting for recovery before freeze\n");
-                       break;
-
-               default:
-                       fs_err(sdp, "error freezing FS: %d\n", error);
-                       break;
-               }
-
-               fs_err(sdp, "retrying...\n");
-               msleep(1000);
-       }
-       return 0;
-}
-
-/**
- * gfs2_unfreeze - reallow writes to the filesystem
- * @sb: the VFS structure for the filesystem
- *
- */
-
-static int gfs2_unfreeze(struct super_block *sb)
-{
-       gfs2_unfreeze_fs(sb->s_fs_info);
-       return 0;
-}
-
-/**
- * statfs_fill - fill in the sg for a given RG
- * @rgd: the RG
- * @sc: the sc structure
- *
- * Returns: 0 on success, -ESTALE if the LVB is invalid
- */
-
-static int statfs_slow_fill(struct gfs2_rgrpd *rgd,
-                           struct gfs2_statfs_change_host *sc)
-{
-       gfs2_rgrp_verify(rgd);
-       sc->sc_total += rgd->rd_data;
-       sc->sc_free += rgd->rd_free;
-       sc->sc_dinodes += rgd->rd_dinodes;
-       return 0;
-}
-
-/**
- * gfs2_statfs_slow - Stat a filesystem using asynchronous locking
- * @sdp: the filesystem
- * @sc: the sc info that will be returned
- *
- * Any error (other than a signal) will cause this routine to fall back
- * to the synchronous version.
- *
- * FIXME: This really shouldn't busy wait like this.
- *
- * Returns: errno
- */
-
-static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *sc)
-{
-       struct gfs2_holder ri_gh;
-       struct gfs2_rgrpd *rgd_next;
-       struct gfs2_holder *gha, *gh;
-       unsigned int slots = 64;
-       unsigned int x;
-       int done;
-       int error = 0, err;
-
-       memset(sc, 0, sizeof(struct gfs2_statfs_change_host));
-       gha = kcalloc(slots, sizeof(struct gfs2_holder), GFP_KERNEL);
-       if (!gha)
-               return -ENOMEM;
-
-       error = gfs2_rindex_hold(sdp, &ri_gh);
-       if (error)
-               goto out;
-
-       rgd_next = gfs2_rgrpd_get_first(sdp);
-
-       for (;;) {
-               done = 1;
-
-               for (x = 0; x < slots; x++) {
-                       gh = gha + x;
-
-                       if (gh->gh_gl && gfs2_glock_poll(gh)) {
-                               err = gfs2_glock_wait(gh);
-                               if (err) {
-                                       gfs2_holder_uninit(gh);
-                                       error = err;
-                               } else {
-                                       if (!error)
-                                               error = statfs_slow_fill(
-                                                       gh->gh_gl->gl_object, sc);
-                                       gfs2_glock_dq_uninit(gh);
-                               }
-                       }
-
-                       if (gh->gh_gl)
-                               done = 0;
-                       else if (rgd_next && !error) {
-                               error = gfs2_glock_nq_init(rgd_next->rd_gl,
-                                                          LM_ST_SHARED,
-                                                          GL_ASYNC,
-                                                          gh);
-                               rgd_next = gfs2_rgrpd_get_next(rgd_next);
-                               done = 0;
-                       }
-
-                       if (signal_pending(current))
-                               error = -ERESTARTSYS;
-               }
-
-               if (done)
-                       break;
-
-               yield();
-       }
-
-       gfs2_glock_dq_uninit(&ri_gh);
-
-out:
-       kfree(gha);
-       return error;
-}
-
-/**
- * gfs2_statfs_i - Do a statfs
- * @sdp: the filesystem
- * @sg: the sg structure
- *
- * Returns: errno
- */
-
-static int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *sc)
-{
-       struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master;
-       struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
-
-       spin_lock(&sdp->sd_statfs_spin);
-
-       *sc = *m_sc;
-       sc->sc_total += l_sc->sc_total;
-       sc->sc_free += l_sc->sc_free;
-       sc->sc_dinodes += l_sc->sc_dinodes;
-
-       spin_unlock(&sdp->sd_statfs_spin);
-
-       if (sc->sc_free < 0)
-               sc->sc_free = 0;
-       if (sc->sc_free > sc->sc_total)
-               sc->sc_free = sc->sc_total;
-       if (sc->sc_dinodes < 0)
-               sc->sc_dinodes = 0;
-
-       return 0;
-}
-
-/**
- * gfs2_statfs - Gather and return stats about the filesystem
- * @sb: The superblock
- * @statfsbuf: The buffer
- *
- * Returns: 0 on success or error code
- */
-
-static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
-{
-       struct super_block *sb = dentry->d_inode->i_sb;
-       struct gfs2_sbd *sdp = sb->s_fs_info;
-       struct gfs2_statfs_change_host sc;
-       int error;
-
-       if (gfs2_tune_get(sdp, gt_statfs_slow))
-               error = gfs2_statfs_slow(sdp, &sc);
-       else
-               error = gfs2_statfs_i(sdp, &sc);
-
-       if (error)
-               return error;
-
-       buf->f_type = GFS2_MAGIC;
-       buf->f_bsize = sdp->sd_sb.sb_bsize;
-       buf->f_blocks = sc.sc_total;
-       buf->f_bfree = sc.sc_free;
-       buf->f_bavail = sc.sc_free;
-       buf->f_files = sc.sc_dinodes + sc.sc_free;
-       buf->f_ffree = sc.sc_free;
-       buf->f_namelen = GFS2_FNAMESIZE;
-
-       return 0;
-}
-
-/**
- * gfs2_remount_fs - called when the FS is remounted
- * @sb:  the filesystem
- * @flags:  the remount flags
- * @data:  extra data passed in (not used right now)
- *
- * Returns: errno
- */
-
-static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
-{
-       struct gfs2_sbd *sdp = sb->s_fs_info;
-       struct gfs2_args args = sdp->sd_args; /* Default to current settings */
-       int error;
-
-       error = gfs2_mount_args(sdp, &args, data);
-       if (error)
-               return error;
-
-       /* Not allowed to change locking details */
-       if (strcmp(args.ar_lockproto, sdp->sd_args.ar_lockproto) ||
-           strcmp(args.ar_locktable, sdp->sd_args.ar_locktable) ||
-           strcmp(args.ar_hostdata, sdp->sd_args.ar_hostdata))
-               return -EINVAL;
-
-       /* Some flags must not be changed */
-       if (args_neq(&args, &sdp->sd_args, spectator) ||
-           args_neq(&args, &sdp->sd_args, ignore_local_fs) ||
-           args_neq(&args, &sdp->sd_args, localflocks) ||
-           args_neq(&args, &sdp->sd_args, localcaching) ||
-           args_neq(&args, &sdp->sd_args, meta))
-               return -EINVAL;
-
-       if (sdp->sd_args.ar_spectator)
-               *flags |= MS_RDONLY;
-
-       if ((sb->s_flags ^ *flags) & MS_RDONLY) {
-               if (*flags & MS_RDONLY)
-                       error = gfs2_make_fs_ro(sdp);
-               else
-                       error = gfs2_make_fs_rw(sdp);
-               if (error)
-                       return error;
-       }
-
-       sdp->sd_args = args;
-       if (sdp->sd_args.ar_posix_acl)
-               sb->s_flags |= MS_POSIXACL;
-       else
-               sb->s_flags &= ~MS_POSIXACL;
-       return 0;
-}
-
-/**
- * gfs2_drop_inode - Drop an inode (test for remote unlink)
- * @inode: The inode to drop
- *
- * If we've received a callback on an iopen lock then its because a
- * remote node tried to deallocate the inode but failed due to this node
- * still having the inode open. Here we mark the link count zero
- * since we know that it must have reached zero if the GLF_DEMOTE flag
- * is set on the iopen glock. If we didn't do a disk read since the
- * remote node removed the final link then we might otherwise miss
- * this event. This check ensures that this node will deallocate the
- * inode's blocks, or alternatively pass the baton on to another
- * node for later deallocation.
- */
-
-static void gfs2_drop_inode(struct inode *inode)
-{
-       struct gfs2_inode *ip = GFS2_I(inode);
-
-       if (test_bit(GIF_USER, &ip->i_flags) && inode->i_nlink) {
-               struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl;
-               if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags))
-                       clear_nlink(inode);
-       }
-       generic_drop_inode(inode);
-}
-
-/**
- * gfs2_clear_inode - Deallocate an inode when VFS is done with it
- * @inode: The VFS inode
- *
- */
-
-static void gfs2_clear_inode(struct inode *inode)
-{
-       struct gfs2_inode *ip = GFS2_I(inode);
-
-       /* This tells us its a "real" inode and not one which only
-        * serves to contain an address space (see rgrp.c, meta_io.c)
-        * which therefore doesn't have its own glocks.
-        */
-       if (test_bit(GIF_USER, &ip->i_flags)) {
-               ip->i_gl->gl_object = NULL;
-               gfs2_glock_put(ip->i_gl);
-               ip->i_gl = NULL;
-               if (ip->i_iopen_gh.gh_gl) {
-                       ip->i_iopen_gh.gh_gl->gl_object = NULL;
-                       gfs2_glock_dq_uninit(&ip->i_iopen_gh);
-               }
-       }
-}
-
-static int is_ancestor(const struct dentry *d1, const struct dentry *d2)
-{
-       do {
-               if (d1 == d2)
-                       return 1;
-               d1 = d1->d_parent;
-       } while (!IS_ROOT(d1));
-       return 0;
-}
-
-/**
- * gfs2_show_options - Show mount options for /proc/mounts
- * @s: seq_file structure
- * @mnt: vfsmount
- *
- * Returns: 0 on success or error code
- */
-
-static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
-{
-       struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info;
-       struct gfs2_args *args = &sdp->sd_args;
-
-       if (is_ancestor(mnt->mnt_root, sdp->sd_master_dir))
-               seq_printf(s, ",meta");
-       if (args->ar_lockproto[0])
-               seq_printf(s, ",lockproto=%s", args->ar_lockproto);
-       if (args->ar_locktable[0])
-               seq_printf(s, ",locktable=%s", args->ar_locktable);
-       if (args->ar_hostdata[0])
-               seq_printf(s, ",hostdata=%s", args->ar_hostdata);
-       if (args->ar_spectator)
-               seq_printf(s, ",spectator");
-       if (args->ar_ignore_local_fs)
-               seq_printf(s, ",ignore_local_fs");
-       if (args->ar_localflocks)
-               seq_printf(s, ",localflocks");
-       if (args->ar_localcaching)
-               seq_printf(s, ",localcaching");
-       if (args->ar_debug)
-               seq_printf(s, ",debug");
-       if (args->ar_upgrade)
-               seq_printf(s, ",upgrade");
-       if (args->ar_posix_acl)
-               seq_printf(s, ",acl");
-       if (args->ar_quota != GFS2_QUOTA_DEFAULT) {
-               char *state;
-               switch (args->ar_quota) {
-               case GFS2_QUOTA_OFF:
-                       state = "off";
-                       break;
-               case GFS2_QUOTA_ACCOUNT:
-                       state = "account";
-                       break;
-               case GFS2_QUOTA_ON:
-                       state = "on";
-                       break;
-               default:
-                       state = "unknown";
-                       break;
-               }
-               seq_printf(s, ",quota=%s", state);
-       }
-       if (args->ar_suiddir)
-               seq_printf(s, ",suiddir");
-       if (args->ar_data != GFS2_DATA_DEFAULT) {
-               char *state;
-               switch (args->ar_data) {
-               case GFS2_DATA_WRITEBACK:
-                       state = "writeback";
-                       break;
-               case GFS2_DATA_ORDERED:
-                       state = "ordered";
-                       break;
-               default:
-                       state = "unknown";
-                       break;
-               }
-               seq_printf(s, ",data=%s", state);
-       }
-       if (args->ar_discard)
-               seq_printf(s, ",discard");
-
-       return 0;
-}
-
-/*
- * We have to (at the moment) hold the inodes main lock to cover
- * the gap between unlocking the shared lock on the iopen lock and
- * taking the exclusive lock. I'd rather do a shared -> exclusive
- * conversion on the iopen lock, but we can change that later. This
- * is safe, just less efficient.
- */
-
-static void gfs2_delete_inode(struct inode *inode)
-{
-       struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
-       struct gfs2_inode *ip = GFS2_I(inode);
-       struct gfs2_holder gh;
-       int error;
-
-       if (!test_bit(GIF_USER, &ip->i_flags))
-               goto out;
-
-       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
-       if (unlikely(error)) {
-               gfs2_glock_dq_uninit(&ip->i_iopen_gh);
-               goto out;
-       }
-
-       gfs2_glock_dq_wait(&ip->i_iopen_gh);
-       gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh);
-       error = gfs2_glock_nq(&ip->i_iopen_gh);
-       if (error)
-               goto out_truncate;
-
-       if (S_ISDIR(inode->i_mode) &&
-           (ip->i_diskflags & GFS2_DIF_EXHASH)) {
-               error = gfs2_dir_exhash_dealloc(ip);
-               if (error)
-                       goto out_unlock;
-       }
-
-       if (ip->i_eattr) {
-               error = gfs2_ea_dealloc(ip);
-               if (error)
-                       goto out_unlock;
-       }
-
-       if (!gfs2_is_stuffed(ip)) {
-               error = gfs2_file_dealloc(ip);
-               if (error)
-                       goto out_unlock;
-       }
-
-       error = gfs2_dinode_dealloc(ip);
-       if (error)
-               goto out_unlock;
-
-out_truncate:
-       error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
-       if (error)
-               goto out_unlock;
-       /* Needs to be done before glock release & also in a transaction */
-       truncate_inode_pages(&inode->i_data, 0);
-       gfs2_trans_end(sdp);
-
-out_unlock:
-       if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags))
-               gfs2_glock_dq(&ip->i_iopen_gh);
-       gfs2_holder_uninit(&ip->i_iopen_gh);
-       gfs2_glock_dq_uninit(&gh);
-       if (error && error != GLR_TRYFAILED)
-               fs_warn(sdp, "gfs2_delete_inode: %d\n", error);
-out:
-       truncate_inode_pages(&inode->i_data, 0);
-       clear_inode(inode);
-}
-
-static struct inode *gfs2_alloc_inode(struct super_block *sb)
-{
-       struct gfs2_inode *ip;
-
-       ip = kmem_cache_alloc(gfs2_inode_cachep, GFP_KERNEL);
-       if (ip) {
-               ip->i_flags = 0;
-               ip->i_gl = NULL;
-       }
-       return &ip->i_inode;
-}
-
-static void gfs2_destroy_inode(struct inode *inode)
-{
-       kmem_cache_free(gfs2_inode_cachep, inode);
-}
-
-const struct super_operations gfs2_super_ops = {
-       .alloc_inode            = gfs2_alloc_inode,
-       .destroy_inode          = gfs2_destroy_inode,
-       .write_inode            = gfs2_write_inode,
-       .delete_inode           = gfs2_delete_inode,
-       .put_super              = gfs2_put_super,
-       .write_super            = gfs2_write_super,
-       .sync_fs                = gfs2_sync_fs,
-       .freeze_fs              = gfs2_freeze,
-       .unfreeze_fs            = gfs2_unfreeze,
-       .statfs                 = gfs2_statfs,
-       .remount_fs             = gfs2_remount_fs,
-       .clear_inode            = gfs2_clear_inode,
-       .drop_inode             = gfs2_drop_inode,
-       .show_options           = gfs2_show_options,
-};
-
index 152e6c4a0dca2b467df51d1eb9defa92a903ffab..2e9b9326bfc96bfe2efbbedf410aae992cd5aa58 100644 (file)
@@ -60,7 +60,6 @@
 #include "super.h"
 #include "trans.h"
 #include "inode.h"
-#include "ops_address.h"
 #include "util.h"
 
 #define QUOTA_USER 1
index 247e8f7d6b3d5da3d23a717ae46d1cadf1bc106e..59d2695509d30c0fd876175f32fe34ec96f29582 100644 (file)
@@ -13,8 +13,7 @@
 #include <linux/buffer_head.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
+#include <linux/slow-work.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -441,18 +440,25 @@ static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
         kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
 }
 
-/**
- * gfs2_recover_journal - recover a given journal
- * @jd: the struct gfs2_jdesc describing the journal
- *
- * Acquire the journal's lock, check to see if the journal is clean, and
- * do recovery if necessary.
- *
- * Returns: errno
- */
+static int gfs2_recover_get_ref(struct slow_work *work)
+{
+       struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
+       if (test_and_set_bit(JDF_RECOVERY, &jd->jd_flags))
+               return -EBUSY;
+       return 0;
+}
 
-int gfs2_recover_journal(struct gfs2_jdesc *jd)
+static void gfs2_recover_put_ref(struct slow_work *work)
+{
+       struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
+       clear_bit(JDF_RECOVERY, &jd->jd_flags);
+       smp_mb__after_clear_bit();
+       wake_up_bit(&jd->jd_flags, JDF_RECOVERY);
+}
+
+static void gfs2_recover_work(struct slow_work *work)
 {
+       struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
        struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
        struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
        struct gfs2_log_header_host head;
@@ -569,7 +575,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd)
                gfs2_glock_dq_uninit(&j_gh);
 
        fs_info(sdp, "jid=%u: Done\n", jd->jd_jid);
-       return 0;
+       return;
 
 fail_gunlock_tr:
        gfs2_glock_dq_uninit(&t_gh);
@@ -584,70 +590,28 @@ fail_gunlock_j:
 
 fail:
        gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP);
-       return error;
 }
 
-static struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp)
-{
-       struct gfs2_jdesc *jd;
-       int found = 0;
-
-       spin_lock(&sdp->sd_jindex_spin);
+struct slow_work_ops gfs2_recover_ops = {
+       .get_ref = gfs2_recover_get_ref,
+       .put_ref = gfs2_recover_put_ref,
+       .execute = gfs2_recover_work,
+};
 
-       list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
-               if (jd->jd_dirty) {
-                       jd->jd_dirty = 0;
-                       found = 1;
-                       break;
-               }
-       }
-       spin_unlock(&sdp->sd_jindex_spin);
-
-       if (!found)
-               jd = NULL;
 
-       return jd;
-}
-
-/**
- * gfs2_check_journals - Recover any dirty journals
- * @sdp: the filesystem
- *
- */
-
-static void gfs2_check_journals(struct gfs2_sbd *sdp)
+static int gfs2_recovery_wait(void *word)
 {
-       struct gfs2_jdesc *jd;
-
-       for (;;) {
-               jd = gfs2_jdesc_find_dirty(sdp);
-               if (!jd)
-                       break;
-
-               if (jd != sdp->sd_jdesc)
-                       gfs2_recover_journal(jd);
-       }
+       schedule();
+       return 0;
 }
 
-/**
- * gfs2_recoverd - Recover dead machine's journals
- * @sdp: Pointer to GFS2 superblock
- *
- */
-
-int gfs2_recoverd(void *data)
+int gfs2_recover_journal(struct gfs2_jdesc *jd)
 {
-       struct gfs2_sbd *sdp = data;
-       unsigned long t;
-
-       while (!kthread_should_stop()) {
-               gfs2_check_journals(sdp);
-               t = gfs2_tune_get(sdp,  gt_recoverd_secs) * HZ;
-               if (freezing(current))
-                       refrigerator();
-               schedule_timeout_interruptible(t);
-       }
-
+       int rv;
+       rv = slow_work_enqueue(&jd->jd_work);
+       if (rv)
+               return rv;
+       wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait, TASK_UNINTERRUPTIBLE);
        return 0;
 }
 
index a8218ea15b57d1793a7eb0a15cb90e499cf74117..1616ac22569a940726c6123ef349ca8e157633d0 100644 (file)
@@ -28,7 +28,7 @@ extern void gfs2_revoke_clean(struct gfs2_sbd *sdp);
 extern int gfs2_find_jhead(struct gfs2_jdesc *jd,
                    struct gfs2_log_header_host *head);
 extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd);
-extern int gfs2_recoverd(void *data);
+extern struct slow_work_ops gfs2_recover_ops;
 
 #endif /* __RECOVERY_DOT_H__ */
 
index 565038243fa2bcc6139ceb5b2bcfeeb107df6c73..de3239731db8c0bcd0e41a57f6850313edb5774b 100644 (file)
@@ -29,7 +29,6 @@
 #include "util.h"
 #include "log.h"
 #include "inode.h"
-#include "ops_address.h"
 
 #define BFITNOENT ((u32)~0)
 #define NO_BLOCK ((u64)~0)
@@ -442,6 +441,7 @@ static int compute_bitstructs(struct gfs2_rgrpd *rgd)
        for (x = 0; x < length; x++) {
                bi = rgd->rd_bits + x;
 
+               bi->bi_flags = 0;
                /* small rgrp; bitmap stored completely in header block */
                if (length == 1) {
                        bytes = bytes_left;
@@ -580,7 +580,6 @@ static int read_rindex_entry(struct gfs2_inode *ip,
 
        rgd->rd_gl->gl_object = rgd;
        rgd->rd_flags &= ~GFS2_RDF_UPTODATE;
-       rgd->rd_flags |= GFS2_RDF_CHECK;
        return error;
 }
 
@@ -701,10 +700,9 @@ static void gfs2_rgrp_in(struct gfs2_rgrpd *rgd, const void *buf)
        u32 rg_flags;
 
        rg_flags = be32_to_cpu(str->rg_flags);
-       if (rg_flags & GFS2_RGF_NOALLOC)
-               rgd->rd_flags |= GFS2_RDF_NOALLOC;
-       else
-               rgd->rd_flags &= ~GFS2_RDF_NOALLOC;
+       rg_flags &= ~GFS2_RDF_MASK;
+       rgd->rd_flags &= GFS2_RDF_MASK;
+       rgd->rd_flags |= rg_flags;
        rgd->rd_free = be32_to_cpu(str->rg_free);
        rgd->rd_dinodes = be32_to_cpu(str->rg_dinodes);
        rgd->rd_igeneration = be64_to_cpu(str->rg_igeneration);
@@ -713,11 +711,8 @@ static void gfs2_rgrp_in(struct gfs2_rgrpd *rgd, const void *buf)
 static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf)
 {
        struct gfs2_rgrp *str = buf;
-       u32 rg_flags = 0;
 
-       if (rgd->rd_flags & GFS2_RDF_NOALLOC)
-               rg_flags |= GFS2_RGF_NOALLOC;
-       str->rg_flags = cpu_to_be32(rg_flags);
+       str->rg_flags = cpu_to_be32(rgd->rd_flags & ~GFS2_RDF_MASK);
        str->rg_free = cpu_to_be32(rgd->rd_free);
        str->rg_dinodes = cpu_to_be32(rgd->rd_dinodes);
        str->__pad = cpu_to_be32(0);
@@ -775,8 +770,10 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
        }
 
        if (!(rgd->rd_flags & GFS2_RDF_UPTODATE)) {
+               for (x = 0; x < length; x++)
+                       clear_bit(GBF_FULL, &rgd->rd_bits[x].bi_flags);
                gfs2_rgrp_in(rgd, (rgd->rd_bits[0].bi_bh)->b_data);
-               rgd->rd_flags |= GFS2_RDF_UPTODATE;
+               rgd->rd_flags |= (GFS2_RDF_UPTODATE | GFS2_RDF_CHECK);
        }
 
        spin_lock(&sdp->sd_rindex_spin);
@@ -845,7 +842,7 @@ static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
        struct super_block *sb = sdp->sd_vfs;
        struct block_device *bdev = sb->s_bdev;
        const unsigned int sects_per_blk = sdp->sd_sb.sb_bsize /
-                                          bdev_hardsect_size(sb->s_bdev);
+                                          bdev_logical_block_size(sb->s_bdev);
        u64 blk;
        sector_t start = 0;
        sector_t nr_sects = 0;
@@ -903,6 +900,7 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd)
                        continue;
                if (sdp->sd_args.ar_discard)
                        gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bi);
+               clear_bit(GBF_FULL, &bi->bi_flags);
                memcpy(bi->bi_clone + bi->bi_offset,
                       bi->bi_bh->b_data + bi->bi_offset, bi->bi_len);
        }
@@ -942,7 +940,7 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al)
        struct gfs2_sbd *sdp = rgd->rd_sbd;
        int ret = 0;
 
-       if (rgd->rd_flags & GFS2_RDF_NOALLOC)
+       if (rgd->rd_flags & (GFS2_RGF_NOALLOC | GFS2_RDF_ERROR))
                return 0;
 
        spin_lock(&sdp->sd_rindex_spin);
@@ -1315,30 +1313,37 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
 {
        struct gfs2_bitmap *bi = NULL;
        const u32 length = rgd->rd_length;
-       u32 blk = 0;
+       u32 blk = BFITNOENT;
        unsigned int buf, x;
        const unsigned int elen = *n;
-       const u8 *buffer;
+       const u8 *buffer = NULL;
 
        *n = 0;
        /* Find bitmap block that contains bits for goal block */
        for (buf = 0; buf < length; buf++) {
                bi = rgd->rd_bits + buf;
-               if (goal < (bi->bi_start + bi->bi_len) * GFS2_NBBY)
-                       break;
+               /* Convert scope of "goal" from rgrp-wide to within found bit block */
+               if (goal < (bi->bi_start + bi->bi_len) * GFS2_NBBY) {
+                       goal -= bi->bi_start * GFS2_NBBY;
+                       goto do_search;
+               }
        }
+       buf = 0;
+       goal = 0;
 
-       gfs2_assert(rgd->rd_sbd, buf < length);
-
-       /* Convert scope of "goal" from rgrp-wide to within found bit block */
-       goal -= bi->bi_start * GFS2_NBBY;
-
+do_search:
        /* Search (up to entire) bitmap in this rgrp for allocatable block.
           "x <= length", instead of "x < length", because we typically start
           the search in the middle of a bit block, but if we can't find an
           allocatable block anywhere else, we want to be able wrap around and
           search in the first part of our first-searched bit block.  */
        for (x = 0; x <= length; x++) {
+               bi = rgd->rd_bits + buf;
+
+               if (test_bit(GBF_FULL, &bi->bi_flags) &&
+                   (old_state == GFS2_BLKST_FREE))
+                       goto skip;
+
                /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
                   bitmaps, so we must search the originals for that. */
                buffer = bi->bi_bh->b_data + bi->bi_offset;
@@ -1349,33 +1354,39 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
                if (blk != BFITNOENT)
                        break;
 
+               if ((goal == 0) && (old_state == GFS2_BLKST_FREE))
+                       set_bit(GBF_FULL, &bi->bi_flags);
+
                /* Try next bitmap block (wrap back to rgrp header if at end) */
-               buf = (buf + 1) % length;
-               bi = rgd->rd_bits + buf;
+skip:
+               buf++;
+               buf %= length;
                goal = 0;
        }
 
-       if (blk != BFITNOENT && old_state != new_state) {
-               *n = 1;
-               gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
+       if (blk == BFITNOENT)
+               return blk;
+       *n = 1;
+       if (old_state == new_state)
+               goto out;
+
+       gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
+       gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, bi->bi_offset,
+                   bi->bi_len, blk, new_state);
+       goal = blk;
+       while (*n < elen) {
+               goal++;
+               if (goal >= (bi->bi_len * GFS2_NBBY))
+                       break;
+               if (gfs2_testbit(rgd, buffer, bi->bi_len, goal) !=
+                   GFS2_BLKST_FREE)
+                       break;
                gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, bi->bi_offset,
-                           bi->bi_len, blk, new_state);
-               goal = blk;
-               while (*n < elen) {
-                       goal++;
-                       if (goal >= (bi->bi_len * GFS2_NBBY))
-                               break;
-                       if (gfs2_testbit(rgd, buffer, bi->bi_len, goal) !=
-                           GFS2_BLKST_FREE)
-                               break;
-                       gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone,
-                                   bi->bi_offset, bi->bi_len, goal,
-                                   new_state);
-                       (*n)++;
-               }
+                           bi->bi_len, goal, new_state);
+               (*n)++;
        }
-
-       return (blk == BFITNOENT) ? blk : (bi->bi_start * GFS2_NBBY) + blk;
+out:
+       return (bi->bi_start * GFS2_NBBY) + blk;
 }
 
 /**
@@ -1435,13 +1446,33 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
 }
 
 /**
- * gfs2_alloc_block - Allocate a block
+ * gfs2_rgrp_dump - print out an rgrp
+ * @seq: The iterator
+ * @gl: The glock in question
+ *
+ */
+
+int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl)
+{
+       const struct gfs2_rgrpd *rgd = gl->gl_object;
+       if (rgd == NULL)
+               return 0;
+       gfs2_print_dbg(seq, " R: n:%llu f:%02x b:%u/%u i:%u\n",
+                      (unsigned long long)rgd->rd_addr, rgd->rd_flags,
+                      rgd->rd_free, rgd->rd_free_clone, rgd->rd_dinodes);
+       return 0;
+}
+
+/**
+ * gfs2_alloc_block - Allocate one or more blocks
  * @ip: the inode to allocate the block for
+ * @bn: Used to return the starting block number
+ * @n: requested number of blocks/extent length (value/result)
  *
- * Returns: the allocated block
+ * Returns: 0 or error
  */
 
-u64 gfs2_alloc_block(struct gfs2_inode *ip, unsigned int *n)
+int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct buffer_head *dibh;
@@ -1457,7 +1488,10 @@ u64 gfs2_alloc_block(struct gfs2_inode *ip, unsigned int *n)
                goal = rgd->rd_last_alloc;
 
        blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED, n);
-       BUG_ON(blk == BFITNOENT);
+
+       /* Since all blocks are reserved in advance, this shouldn't happen */
+       if (blk == BFITNOENT)
+               goto rgrp_error;
 
        rgd->rd_last_alloc = blk;
        block = rgd->rd_data0 + blk;
@@ -1469,7 +1503,9 @@ u64 gfs2_alloc_block(struct gfs2_inode *ip, unsigned int *n)
                di->di_goal_meta = di->di_goal_data = cpu_to_be64(ip->i_goal);
                brelse(dibh);
        }
-       gfs2_assert_withdraw(sdp, rgd->rd_free >= *n);
+       if (rgd->rd_free < *n)
+               goto rgrp_error;
+
        rgd->rd_free -= *n;
 
        gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
@@ -1484,7 +1520,16 @@ u64 gfs2_alloc_block(struct gfs2_inode *ip, unsigned int *n)
        rgd->rd_free_clone -= *n;
        spin_unlock(&sdp->sd_rindex_spin);
 
-       return block;
+       *bn = block;
+       return 0;
+
+rgrp_error:
+       fs_warn(sdp, "rgrp %llu has an error, marking it readonly until umount\n",
+               (unsigned long long)rgd->rd_addr);
+       fs_warn(sdp, "umount on all nodes and run fsck.gfs2 to fix the error\n");
+       gfs2_rgrp_dump(NULL, rgd->rd_gl);
+       rgd->rd_flags |= GFS2_RDF_ERROR;
+       return -EIO;
 }
 
 /**
index 3181c7e624bffd7b2666910c714007c525996505..1e76ff0f3e00cf24328dbb169b0b38bdff14d25c 100644 (file)
@@ -14,22 +14,22 @@ struct gfs2_rgrpd;
 struct gfs2_sbd;
 struct gfs2_holder;
 
-void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd);
+extern void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd);
 
 struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk);
 struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp);
 struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
 
-void gfs2_clear_rgrpd(struct gfs2_sbd *sdp);
-int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh);
+extern void gfs2_clear_rgrpd(struct gfs2_sbd *sdp);
+extern int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh);
 
-int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd);
-void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd);
-void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd);
+extern int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd);
+extern void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd);
+extern void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd);
 
-void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd);
+extern void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd);
 
-struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
+extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
 static inline void gfs2_alloc_put(struct gfs2_inode *ip)
 {
        BUG_ON(ip->i_alloc == NULL);
@@ -37,22 +37,22 @@ static inline void gfs2_alloc_put(struct gfs2_inode *ip)
        ip->i_alloc = NULL;
 }
 
-int gfs2_inplace_reserve_i(struct gfs2_inode *ip,
-                        char *file, unsigned int line);
+extern int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file,
+                                 unsigned int line);
 #define gfs2_inplace_reserve(ip) \
 gfs2_inplace_reserve_i((ip), __FILE__, __LINE__)
 
-void gfs2_inplace_release(struct gfs2_inode *ip);
+extern void gfs2_inplace_release(struct gfs2_inode *ip);
 
-unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block);
+extern unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block);
 
-u64 gfs2_alloc_block(struct gfs2_inode *ip, unsigned int *n);
-u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation);
+extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n);
+extern u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation);
 
-void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen);
-void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen);
-void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip);
-void gfs2_unlink_di(struct inode *inode);
+extern void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen);
+extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen);
+extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip);
+extern void gfs2_unlink_di(struct inode *inode);
 
 struct gfs2_rgrp_list {
        unsigned int rl_rgrps;
@@ -61,10 +61,11 @@ struct gfs2_rgrp_list {
        struct gfs2_holder *rl_ghs;
 };
 
-void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
-                   u64 block);
-void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state);
-void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
-u64 gfs2_ri_total(struct gfs2_sbd *sdp);
+extern void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
+                          u64 block);
+extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state);
+extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
+extern u64 gfs2_ri_total(struct gfs2_sbd *sdp);
+extern int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl);
 
 #endif /* __RGRP_DOT_H__ */
index 601913e0a482901099ebb495b230df8f7805cd92..40bcc37e5a700e525ab9c72ab24b0295329de6ba 100644 (file)
@@ -7,14 +7,20 @@
  * of the GNU General Public License version 2.
  */
 
+#include <linux/bio.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/buffer_head.h>
-#include <linux/crc32.h>
+#include <linux/statfs.h>
+#include <linux/seq_file.h>
+#include <linux/mount.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/bio.h>
+#include <linux/crc32.h>
+#include <linux/time.h>
 
 #include "gfs2.h"
 #include "incore.h"
 #include "super.h"
 #include "trans.h"
 #include "util.h"
+#include "sys.h"
+#include "eattr.h"
+
+#define args_neq(a1, a2, x) ((a1)->ar_##x != (a2)->ar_##x)
+
+enum {
+       Opt_lockproto,
+       Opt_locktable,
+       Opt_hostdata,
+       Opt_spectator,
+       Opt_ignore_local_fs,
+       Opt_localflocks,
+       Opt_localcaching,
+       Opt_debug,
+       Opt_nodebug,
+       Opt_upgrade,
+       Opt_acl,
+       Opt_noacl,
+       Opt_quota_off,
+       Opt_quota_account,
+       Opt_quota_on,
+       Opt_quota,
+       Opt_noquota,
+       Opt_suiddir,
+       Opt_nosuiddir,
+       Opt_data_writeback,
+       Opt_data_ordered,
+       Opt_meta,
+       Opt_discard,
+       Opt_nodiscard,
+       Opt_commit,
+       Opt_error,
+};
+
+static const match_table_t tokens = {
+       {Opt_lockproto, "lockproto=%s"},
+       {Opt_locktable, "locktable=%s"},
+       {Opt_hostdata, "hostdata=%s"},
+       {Opt_spectator, "spectator"},
+       {Opt_ignore_local_fs, "ignore_local_fs"},
+       {Opt_localflocks, "localflocks"},
+       {Opt_localcaching, "localcaching"},
+       {Opt_debug, "debug"},
+       {Opt_nodebug, "nodebug"},
+       {Opt_upgrade, "upgrade"},
+       {Opt_acl, "acl"},
+       {Opt_noacl, "noacl"},
+       {Opt_quota_off, "quota=off"},
+       {Opt_quota_account, "quota=account"},
+       {Opt_quota_on, "quota=on"},
+       {Opt_quota, "quota"},
+       {Opt_noquota, "noquota"},
+       {Opt_suiddir, "suiddir"},
+       {Opt_nosuiddir, "nosuiddir"},
+       {Opt_data_writeback, "data=writeback"},
+       {Opt_data_ordered, "data=ordered"},
+       {Opt_meta, "meta"},
+       {Opt_discard, "discard"},
+       {Opt_nodiscard, "nodiscard"},
+       {Opt_commit, "commit=%d"},
+       {Opt_error, NULL}
+};
+
+/**
+ * gfs2_mount_args - Parse mount options
+ * @sdp:
+ * @data:
+ *
+ * Return: errno
+ */
+
+int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
+{
+       char *o;
+       int token;
+       substring_t tmp[MAX_OPT_ARGS];
+       int rv;
+
+       /* Split the options into tokens with the "," character and
+          process them */
+
+       while (1) {
+               o = strsep(&options, ",");
+               if (o == NULL)
+                       break;
+               if (*o == '\0')
+                       continue;
+
+               token = match_token(o, tokens, tmp);
+               switch (token) {
+               case Opt_lockproto:
+                       match_strlcpy(args->ar_lockproto, &tmp[0],
+                                     GFS2_LOCKNAME_LEN);
+                       break;
+               case Opt_locktable:
+                       match_strlcpy(args->ar_locktable, &tmp[0],
+                                     GFS2_LOCKNAME_LEN);
+                       break;
+               case Opt_hostdata:
+                       match_strlcpy(args->ar_hostdata, &tmp[0],
+                                     GFS2_LOCKNAME_LEN);
+                       break;
+               case Opt_spectator:
+                       args->ar_spectator = 1;
+                       break;
+               case Opt_ignore_local_fs:
+                       args->ar_ignore_local_fs = 1;
+                       break;
+               case Opt_localflocks:
+                       args->ar_localflocks = 1;
+                       break;
+               case Opt_localcaching:
+                       args->ar_localcaching = 1;
+                       break;
+               case Opt_debug:
+                       args->ar_debug = 1;
+                       break;
+               case Opt_nodebug:
+                       args->ar_debug = 0;
+                       break;
+               case Opt_upgrade:
+                       args->ar_upgrade = 1;
+                       break;
+               case Opt_acl:
+                       args->ar_posix_acl = 1;
+                       break;
+               case Opt_noacl:
+                       args->ar_posix_acl = 0;
+                       break;
+               case Opt_quota_off:
+               case Opt_noquota:
+                       args->ar_quota = GFS2_QUOTA_OFF;
+                       break;
+               case Opt_quota_account:
+                       args->ar_quota = GFS2_QUOTA_ACCOUNT;
+                       break;
+               case Opt_quota_on:
+               case Opt_quota:
+                       args->ar_quota = GFS2_QUOTA_ON;
+                       break;
+               case Opt_suiddir:
+                       args->ar_suiddir = 1;
+                       break;
+               case Opt_nosuiddir:
+                       args->ar_suiddir = 0;
+                       break;
+               case Opt_data_writeback:
+                       args->ar_data = GFS2_DATA_WRITEBACK;
+                       break;
+               case Opt_data_ordered:
+                       args->ar_data = GFS2_DATA_ORDERED;
+                       break;
+               case Opt_meta:
+                       args->ar_meta = 1;
+                       break;
+               case Opt_discard:
+                       args->ar_discard = 1;
+                       break;
+               case Opt_nodiscard:
+                       args->ar_discard = 0;
+                       break;
+               case Opt_commit:
+                       rv = match_int(&tmp[0], &args->ar_commit);
+                       if (rv || args->ar_commit <= 0) {
+                               fs_info(sdp, "commit mount option requires a positive numeric argument\n");
+                               return rv ? rv : -EINVAL;
+                       }
+                       break;
+               case Opt_error:
+               default:
+                       fs_info(sdp, "invalid mount option: %s\n", o);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
 
 /**
  * gfs2_jindex_free - Clear all the journal index information
@@ -436,3 +619,719 @@ void gfs2_unfreeze_fs(struct gfs2_sbd *sdp)
        mutex_unlock(&sdp->sd_freeze_lock);
 }
 
+
+/**
+ * gfs2_write_inode - Make sure the inode is stable on the disk
+ * @inode: The inode
+ * @sync: synchronous write flag
+ *
+ * Returns: errno
+ */
+
+static int gfs2_write_inode(struct inode *inode, int sync)
+{
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
+       struct gfs2_holder gh;
+       struct buffer_head *bh;
+       struct timespec atime;
+       struct gfs2_dinode *di;
+       int ret = 0;
+
+       /* Check this is a "normal" inode, etc */
+       if (!test_bit(GIF_USER, &ip->i_flags) ||
+           (current->flags & PF_MEMALLOC))
+               return 0;
+       ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
+       if (ret)
+               goto do_flush;
+       ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
+       if (ret)
+               goto do_unlock;
+       ret = gfs2_meta_inode_buffer(ip, &bh);
+       if (ret == 0) {
+               di = (struct gfs2_dinode *)bh->b_data;
+               atime.tv_sec = be64_to_cpu(di->di_atime);
+               atime.tv_nsec = be32_to_cpu(di->di_atime_nsec);
+               if (timespec_compare(&inode->i_atime, &atime) > 0) {
+                       gfs2_trans_add_bh(ip->i_gl, bh, 1);
+                       gfs2_dinode_out(ip, bh->b_data);
+               }
+               brelse(bh);
+       }
+       gfs2_trans_end(sdp);
+do_unlock:
+       gfs2_glock_dq_uninit(&gh);
+do_flush:
+       if (sync != 0)
+               gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
+       return ret;
+}
+
+/**
+ * gfs2_make_fs_ro - Turn a Read-Write FS into a Read-Only one
+ * @sdp: the filesystem
+ *
+ * Returns: errno
+ */
+
+static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
+{
+       struct gfs2_holder t_gh;
+       int error;
+
+       gfs2_quota_sync(sdp);
+       gfs2_statfs_sync(sdp);
+
+       error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE,
+                                  &t_gh);
+       if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
+               return error;
+
+       gfs2_meta_syncfs(sdp);
+       gfs2_log_shutdown(sdp);
+
+       clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
+
+       if (t_gh.gh_gl)
+               gfs2_glock_dq_uninit(&t_gh);
+
+       gfs2_quota_cleanup(sdp);
+
+       return error;
+}
+
+static int gfs2_umount_recovery_wait(void *word)
+{
+       schedule();
+       return 0;
+}
+
+/**
+ * gfs2_put_super - Unmount the filesystem
+ * @sb: The VFS superblock
+ *
+ */
+
+static void gfs2_put_super(struct super_block *sb)
+{
+       struct gfs2_sbd *sdp = sb->s_fs_info;
+       int error;
+       struct gfs2_jdesc *jd;
+
+       /*  Unfreeze the filesystem, if we need to  */
+
+       mutex_lock(&sdp->sd_freeze_lock);
+       if (sdp->sd_freeze_count)
+               gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
+       mutex_unlock(&sdp->sd_freeze_lock);
+
+       /* No more recovery requests */
+       set_bit(SDF_NORECOVERY, &sdp->sd_flags);
+       smp_mb();
+
+       /* Wait on outstanding recovery */
+restart:
+       spin_lock(&sdp->sd_jindex_spin);
+       list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
+               if (!test_bit(JDF_RECOVERY, &jd->jd_flags))
+                       continue;
+               spin_unlock(&sdp->sd_jindex_spin);
+               wait_on_bit(&jd->jd_flags, JDF_RECOVERY,
+                           gfs2_umount_recovery_wait, TASK_UNINTERRUPTIBLE);
+               goto restart;
+       }
+       spin_unlock(&sdp->sd_jindex_spin);
+
+       kthread_stop(sdp->sd_quotad_process);
+       kthread_stop(sdp->sd_logd_process);
+
+       if (!(sb->s_flags & MS_RDONLY)) {
+               error = gfs2_make_fs_ro(sdp);
+               if (error)
+                       gfs2_io_error(sdp);
+       }
+       /*  At this point, we're through modifying the disk  */
+
+       /*  Release stuff  */
+
+       iput(sdp->sd_jindex);
+       iput(sdp->sd_inum_inode);
+       iput(sdp->sd_statfs_inode);
+       iput(sdp->sd_rindex);
+       iput(sdp->sd_quota_inode);
+
+       gfs2_glock_put(sdp->sd_rename_gl);
+       gfs2_glock_put(sdp->sd_trans_gl);
+
+       if (!sdp->sd_args.ar_spectator) {
+               gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
+               gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
+               gfs2_glock_dq_uninit(&sdp->sd_ir_gh);
+               gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
+               gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
+               iput(sdp->sd_ir_inode);
+               iput(sdp->sd_sc_inode);
+               iput(sdp->sd_qc_inode);
+       }
+
+       gfs2_glock_dq_uninit(&sdp->sd_live_gh);
+       gfs2_clear_rgrpd(sdp);
+       gfs2_jindex_free(sdp);
+       /*  Take apart glock structures and buffer lists  */
+       gfs2_gl_hash_clear(sdp);
+       /*  Unmount the locking protocol  */
+       gfs2_lm_unmount(sdp);
+
+       /*  At this point, we're through participating in the lockspace  */
+       gfs2_sys_fs_del(sdp);
+}
+
+/**
+ * gfs2_write_super
+ * @sb: the superblock
+ *
+ */
+
+static void gfs2_write_super(struct super_block *sb)
+{
+       sb->s_dirt = 0;
+}
+
+/**
+ * gfs2_sync_fs - sync the filesystem
+ * @sb: the superblock
+ *
+ * Flushes the log to disk.
+ */
+
+static int gfs2_sync_fs(struct super_block *sb, int wait)
+{
+       sb->s_dirt = 0;
+       if (wait && sb->s_fs_info)
+               gfs2_log_flush(sb->s_fs_info, NULL);
+       return 0;
+}
+
+/**
+ * gfs2_freeze - prevent further writes to the filesystem
+ * @sb: the VFS structure for the filesystem
+ *
+ */
+
+static int gfs2_freeze(struct super_block *sb)
+{
+       struct gfs2_sbd *sdp = sb->s_fs_info;
+       int error;
+
+       if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
+               return -EINVAL;
+
+       for (;;) {
+               error = gfs2_freeze_fs(sdp);
+               if (!error)
+                       break;
+
+               switch (error) {
+               case -EBUSY:
+                       fs_err(sdp, "waiting for recovery before freeze\n");
+                       break;
+
+               default:
+                       fs_err(sdp, "error freezing FS: %d\n", error);
+                       break;
+               }
+
+               fs_err(sdp, "retrying...\n");
+               msleep(1000);
+       }
+       return 0;
+}
+
+/**
+ * gfs2_unfreeze - reallow writes to the filesystem
+ * @sb: the VFS structure for the filesystem
+ *
+ */
+
+static int gfs2_unfreeze(struct super_block *sb)
+{
+       gfs2_unfreeze_fs(sb->s_fs_info);
+       return 0;
+}
+
+/**
+ * statfs_fill - fill in the sg for a given RG
+ * @rgd: the RG
+ * @sc: the sc structure
+ *
+ * Returns: 0 on success, -ESTALE if the LVB is invalid
+ */
+
+static int statfs_slow_fill(struct gfs2_rgrpd *rgd,
+                           struct gfs2_statfs_change_host *sc)
+{
+       gfs2_rgrp_verify(rgd);
+       sc->sc_total += rgd->rd_data;
+       sc->sc_free += rgd->rd_free;
+       sc->sc_dinodes += rgd->rd_dinodes;
+       return 0;
+}
+
+/**
+ * gfs2_statfs_slow - Stat a filesystem using asynchronous locking
+ * @sdp: the filesystem
+ * @sc: the sc info that will be returned
+ *
+ * Any error (other than a signal) will cause this routine to fall back
+ * to the synchronous version.
+ *
+ * FIXME: This really shouldn't busy wait like this.
+ *
+ * Returns: errno
+ */
+
+static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *sc)
+{
+       struct gfs2_holder ri_gh;
+       struct gfs2_rgrpd *rgd_next;
+       struct gfs2_holder *gha, *gh;
+       unsigned int slots = 64;
+       unsigned int x;
+       int done;
+       int error = 0, err;
+
+       memset(sc, 0, sizeof(struct gfs2_statfs_change_host));
+       gha = kcalloc(slots, sizeof(struct gfs2_holder), GFP_KERNEL);
+       if (!gha)
+               return -ENOMEM;
+
+       error = gfs2_rindex_hold(sdp, &ri_gh);
+       if (error)
+               goto out;
+
+       rgd_next = gfs2_rgrpd_get_first(sdp);
+
+       for (;;) {
+               done = 1;
+
+               for (x = 0; x < slots; x++) {
+                       gh = gha + x;
+
+                       if (gh->gh_gl && gfs2_glock_poll(gh)) {
+                               err = gfs2_glock_wait(gh);
+                               if (err) {
+                                       gfs2_holder_uninit(gh);
+                                       error = err;
+                               } else {
+                                       if (!error)
+                                               error = statfs_slow_fill(
+                                                       gh->gh_gl->gl_object, sc);
+                                       gfs2_glock_dq_uninit(gh);
+                               }
+                       }
+
+                       if (gh->gh_gl)
+                               done = 0;
+                       else if (rgd_next && !error) {
+                               error = gfs2_glock_nq_init(rgd_next->rd_gl,
+                                                          LM_ST_SHARED,
+                                                          GL_ASYNC,
+                                                          gh);
+                               rgd_next = gfs2_rgrpd_get_next(rgd_next);
+                               done = 0;
+                       }
+
+                       if (signal_pending(current))
+                               error = -ERESTARTSYS;
+               }
+
+               if (done)
+                       break;
+
+               yield();
+       }
+
+       gfs2_glock_dq_uninit(&ri_gh);
+
+out:
+       kfree(gha);
+       return error;
+}
+
+/**
+ * gfs2_statfs_i - Do a statfs
+ * @sdp: the filesystem
+ * @sg: the sg structure
+ *
+ * Returns: errno
+ */
+
+static int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *sc)
+{
+       struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master;
+       struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
+
+       spin_lock(&sdp->sd_statfs_spin);
+
+       *sc = *m_sc;
+       sc->sc_total += l_sc->sc_total;
+       sc->sc_free += l_sc->sc_free;
+       sc->sc_dinodes += l_sc->sc_dinodes;
+
+       spin_unlock(&sdp->sd_statfs_spin);
+
+       if (sc->sc_free < 0)
+               sc->sc_free = 0;
+       if (sc->sc_free > sc->sc_total)
+               sc->sc_free = sc->sc_total;
+       if (sc->sc_dinodes < 0)
+               sc->sc_dinodes = 0;
+
+       return 0;
+}
+
+/**
+ * gfs2_statfs - Gather and return stats about the filesystem
+ * @sb: The superblock
+ * @statfsbuf: The buffer
+ *
+ * Returns: 0 on success or error code
+ */
+
+static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+       struct super_block *sb = dentry->d_inode->i_sb;
+       struct gfs2_sbd *sdp = sb->s_fs_info;
+       struct gfs2_statfs_change_host sc;
+       int error;
+
+       if (gfs2_tune_get(sdp, gt_statfs_slow))
+               error = gfs2_statfs_slow(sdp, &sc);
+       else
+               error = gfs2_statfs_i(sdp, &sc);
+
+       if (error)
+               return error;
+
+       buf->f_type = GFS2_MAGIC;
+       buf->f_bsize = sdp->sd_sb.sb_bsize;
+       buf->f_blocks = sc.sc_total;
+       buf->f_bfree = sc.sc_free;
+       buf->f_bavail = sc.sc_free;
+       buf->f_files = sc.sc_dinodes + sc.sc_free;
+       buf->f_ffree = sc.sc_free;
+       buf->f_namelen = GFS2_FNAMESIZE;
+
+       return 0;
+}
+
+/**
+ * gfs2_remount_fs - called when the FS is remounted
+ * @sb:  the filesystem
+ * @flags:  the remount flags
+ * @data:  extra data passed in (not used right now)
+ *
+ * Returns: errno
+ */
+
+static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+       struct gfs2_sbd *sdp = sb->s_fs_info;
+       struct gfs2_args args = sdp->sd_args; /* Default to current settings */
+       struct gfs2_tune *gt = &sdp->sd_tune;
+       int error;
+
+       spin_lock(&gt->gt_spin);
+       args.ar_commit = gt->gt_log_flush_secs;
+       spin_unlock(&gt->gt_spin);
+       error = gfs2_mount_args(sdp, &args, data);
+       if (error)
+               return error;
+
+       /* Not allowed to change locking details */
+       if (strcmp(args.ar_lockproto, sdp->sd_args.ar_lockproto) ||
+           strcmp(args.ar_locktable, sdp->sd_args.ar_locktable) ||
+           strcmp(args.ar_hostdata, sdp->sd_args.ar_hostdata))
+               return -EINVAL;
+
+       /* Some flags must not be changed */
+       if (args_neq(&args, &sdp->sd_args, spectator) ||
+           args_neq(&args, &sdp->sd_args, ignore_local_fs) ||
+           args_neq(&args, &sdp->sd_args, localflocks) ||
+           args_neq(&args, &sdp->sd_args, localcaching) ||
+           args_neq(&args, &sdp->sd_args, meta))
+               return -EINVAL;
+
+       if (sdp->sd_args.ar_spectator)
+               *flags |= MS_RDONLY;
+
+       if ((sb->s_flags ^ *flags) & MS_RDONLY) {
+               if (*flags & MS_RDONLY)
+                       error = gfs2_make_fs_ro(sdp);
+               else
+                       error = gfs2_make_fs_rw(sdp);
+               if (error)
+                       return error;
+       }
+
+       sdp->sd_args = args;
+       if (sdp->sd_args.ar_posix_acl)
+               sb->s_flags |= MS_POSIXACL;
+       else
+               sb->s_flags &= ~MS_POSIXACL;
+       spin_lock(&gt->gt_spin);
+       gt->gt_log_flush_secs = args.ar_commit;
+       spin_unlock(&gt->gt_spin);
+
+       return 0;
+}
+
+/**
+ * gfs2_drop_inode - Drop an inode (test for remote unlink)
+ * @inode: The inode to drop
+ *
+ * If we've received a callback on an iopen lock then its because a
+ * remote node tried to deallocate the inode but failed due to this node
+ * still having the inode open. Here we mark the link count zero
+ * since we know that it must have reached zero if the GLF_DEMOTE flag
+ * is set on the iopen glock. If we didn't do a disk read since the
+ * remote node removed the final link then we might otherwise miss
+ * this event. This check ensures that this node will deallocate the
+ * inode's blocks, or alternatively pass the baton on to another
+ * node for later deallocation.
+ */
+
+static void gfs2_drop_inode(struct inode *inode)
+{
+       struct gfs2_inode *ip = GFS2_I(inode);
+
+       if (test_bit(GIF_USER, &ip->i_flags) && inode->i_nlink) {
+               struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl;
+               if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags))
+                       clear_nlink(inode);
+       }
+       generic_drop_inode(inode);
+}
+
+/**
+ * gfs2_clear_inode - Deallocate an inode when VFS is done with it
+ * @inode: The VFS inode
+ *
+ */
+
+static void gfs2_clear_inode(struct inode *inode)
+{
+       struct gfs2_inode *ip = GFS2_I(inode);
+
+       /* This tells us its a "real" inode and not one which only
+        * serves to contain an address space (see rgrp.c, meta_io.c)
+        * which therefore doesn't have its own glocks.
+        */
+       if (test_bit(GIF_USER, &ip->i_flags)) {
+               ip->i_gl->gl_object = NULL;
+               gfs2_glock_put(ip->i_gl);
+               ip->i_gl = NULL;
+               if (ip->i_iopen_gh.gh_gl) {
+                       ip->i_iopen_gh.gh_gl->gl_object = NULL;
+                       gfs2_glock_dq_uninit(&ip->i_iopen_gh);
+               }
+       }
+}
+
+static int is_ancestor(const struct dentry *d1, const struct dentry *d2)
+{
+       do {
+               if (d1 == d2)
+                       return 1;
+               d1 = d1->d_parent;
+       } while (!IS_ROOT(d1));
+       return 0;
+}
+
+/**
+ * gfs2_show_options - Show mount options for /proc/mounts
+ * @s: seq_file structure
+ * @mnt: vfsmount
+ *
+ * Returns: 0 on success or error code
+ */
+
+static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
+{
+       struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info;
+       struct gfs2_args *args = &sdp->sd_args;
+       int lfsecs;
+
+       if (is_ancestor(mnt->mnt_root, sdp->sd_master_dir))
+               seq_printf(s, ",meta");
+       if (args->ar_lockproto[0])
+               seq_printf(s, ",lockproto=%s", args->ar_lockproto);
+       if (args->ar_locktable[0])
+               seq_printf(s, ",locktable=%s", args->ar_locktable);
+       if (args->ar_hostdata[0])
+               seq_printf(s, ",hostdata=%s", args->ar_hostdata);
+       if (args->ar_spectator)
+               seq_printf(s, ",spectator");
+       if (args->ar_ignore_local_fs)
+               seq_printf(s, ",ignore_local_fs");
+       if (args->ar_localflocks)
+               seq_printf(s, ",localflocks");
+       if (args->ar_localcaching)
+               seq_printf(s, ",localcaching");
+       if (args->ar_debug)
+               seq_printf(s, ",debug");
+       if (args->ar_upgrade)
+               seq_printf(s, ",upgrade");
+       if (args->ar_posix_acl)
+               seq_printf(s, ",acl");
+       if (args->ar_quota != GFS2_QUOTA_DEFAULT) {
+               char *state;
+               switch (args->ar_quota) {
+               case GFS2_QUOTA_OFF:
+                       state = "off";
+                       break;
+               case GFS2_QUOTA_ACCOUNT:
+                       state = "account";
+                       break;
+               case GFS2_QUOTA_ON:
+                       state = "on";
+                       break;
+               default:
+                       state = "unknown";
+                       break;
+               }
+               seq_printf(s, ",quota=%s", state);
+       }
+       if (args->ar_suiddir)
+               seq_printf(s, ",suiddir");
+       if (args->ar_data != GFS2_DATA_DEFAULT) {
+               char *state;
+               switch (args->ar_data) {
+               case GFS2_DATA_WRITEBACK:
+                       state = "writeback";
+                       break;
+               case GFS2_DATA_ORDERED:
+                       state = "ordered";
+                       break;
+               default:
+                       state = "unknown";
+                       break;
+               }
+               seq_printf(s, ",data=%s", state);
+       }
+       if (args->ar_discard)
+               seq_printf(s, ",discard");
+       lfsecs = sdp->sd_tune.gt_log_flush_secs;
+       if (lfsecs != 60)
+               seq_printf(s, ",commit=%d", lfsecs);
+       return 0;
+}
+
+/*
+ * We have to (at the moment) hold the inodes main lock to cover
+ * the gap between unlocking the shared lock on the iopen lock and
+ * taking the exclusive lock. I'd rather do a shared -> exclusive
+ * conversion on the iopen lock, but we can change that later. This
+ * is safe, just less efficient.
+ */
+
+static void gfs2_delete_inode(struct inode *inode)
+{
+       struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_holder gh;
+       int error;
+
+       if (!test_bit(GIF_USER, &ip->i_flags))
+               goto out;
+
+       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
+       if (unlikely(error)) {
+               gfs2_glock_dq_uninit(&ip->i_iopen_gh);
+               goto out;
+       }
+
+       gfs2_glock_dq_wait(&ip->i_iopen_gh);
+       gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh);
+       error = gfs2_glock_nq(&ip->i_iopen_gh);
+       if (error)
+               goto out_truncate;
+
+       if (S_ISDIR(inode->i_mode) &&
+           (ip->i_diskflags & GFS2_DIF_EXHASH)) {
+               error = gfs2_dir_exhash_dealloc(ip);
+               if (error)
+                       goto out_unlock;
+       }
+
+       if (ip->i_eattr) {
+               error = gfs2_ea_dealloc(ip);
+               if (error)
+                       goto out_unlock;
+       }
+
+       if (!gfs2_is_stuffed(ip)) {
+               error = gfs2_file_dealloc(ip);
+               if (error)
+                       goto out_unlock;
+       }
+
+       error = gfs2_dinode_dealloc(ip);
+       if (error)
+               goto out_unlock;
+
+out_truncate:
+       error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
+       if (error)
+               goto out_unlock;
+       /* Needs to be done before glock release & also in a transaction */
+       truncate_inode_pages(&inode->i_data, 0);
+       gfs2_trans_end(sdp);
+
+out_unlock:
+       if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags))
+               gfs2_glock_dq(&ip->i_iopen_gh);
+       gfs2_holder_uninit(&ip->i_iopen_gh);
+       gfs2_glock_dq_uninit(&gh);
+       if (error && error != GLR_TRYFAILED && error != -EROFS)
+               fs_warn(sdp, "gfs2_delete_inode: %d\n", error);
+out:
+       truncate_inode_pages(&inode->i_data, 0);
+       clear_inode(inode);
+}
+
+static struct inode *gfs2_alloc_inode(struct super_block *sb)
+{
+       struct gfs2_inode *ip;
+
+       ip = kmem_cache_alloc(gfs2_inode_cachep, GFP_KERNEL);
+       if (ip) {
+               ip->i_flags = 0;
+               ip->i_gl = NULL;
+       }
+       return &ip->i_inode;
+}
+
+static void gfs2_destroy_inode(struct inode *inode)
+{
+       kmem_cache_free(gfs2_inode_cachep, inode);
+}
+
+const struct super_operations gfs2_super_ops = {
+       .alloc_inode            = gfs2_alloc_inode,
+       .destroy_inode          = gfs2_destroy_inode,
+       .write_inode            = gfs2_write_inode,
+       .delete_inode           = gfs2_delete_inode,
+       .put_super              = gfs2_put_super,
+       .write_super            = gfs2_write_super,
+       .sync_fs                = gfs2_sync_fs,
+       .freeze_fs              = gfs2_freeze,
+       .unfreeze_fs            = gfs2_unfreeze,
+       .statfs                 = gfs2_statfs,
+       .remount_fs             = gfs2_remount_fs,
+       .clear_inode            = gfs2_clear_inode,
+       .drop_inode             = gfs2_drop_inode,
+       .show_options           = gfs2_show_options,
+};
+
index 7655f5025fec4868e7d00e5790abb5d85394a926..23419dc3027b69659aab64eeb0a6aced7504810e 100644 (file)
 #include "util.h"
 #include "glops.h"
 
+struct gfs2_attr {
+       struct attribute attr;
+       ssize_t (*show)(struct gfs2_sbd *, char *);
+       ssize_t (*store)(struct gfs2_sbd *, const char *, size_t);
+};
+
+static ssize_t gfs2_attr_show(struct kobject *kobj, struct attribute *attr,
+                             char *buf)
+{
+       struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj);
+       struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr);
+       return a->show ? a->show(sdp, buf) : 0;
+}
+
+static ssize_t gfs2_attr_store(struct kobject *kobj, struct attribute *attr,
+                              const char *buf, size_t len)
+{
+       struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj);
+       struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr);
+       return a->store ? a->store(sdp, buf, len) : len;
+}
+
+static struct sysfs_ops gfs2_attr_ops = {
+       .show  = gfs2_attr_show,
+       .store = gfs2_attr_store,
+};
+
+
+static struct kset *gfs2_kset;
+
 static ssize_t id_show(struct gfs2_sbd *sdp, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, "%u:%u\n",
@@ -212,11 +242,6 @@ static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len
        return len;
 }
 
-struct gfs2_attr {
-       struct attribute attr;
-       ssize_t (*show)(struct gfs2_sbd *, char *);
-       ssize_t (*store)(struct gfs2_sbd *, const char *, size_t);
-};
 
 #define GFS2_ATTR(name, mode, show, store) \
 static struct gfs2_attr gfs2_attr_##name = __ATTR(name, mode, show, store)
@@ -246,58 +271,11 @@ static struct attribute *gfs2_attrs[] = {
        NULL,
 };
 
-static ssize_t gfs2_attr_show(struct kobject *kobj, struct attribute *attr,
-                             char *buf)
-{
-       struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj);
-       struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr);
-       return a->show ? a->show(sdp, buf) : 0;
-}
-
-static ssize_t gfs2_attr_store(struct kobject *kobj, struct attribute *attr,
-                              const char *buf, size_t len)
-{
-       struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj);
-       struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr);
-       return a->store ? a->store(sdp, buf, len) : len;
-}
-
-static struct sysfs_ops gfs2_attr_ops = {
-       .show  = gfs2_attr_show,
-       .store = gfs2_attr_store,
-};
-
 static struct kobj_type gfs2_ktype = {
        .default_attrs = gfs2_attrs,
        .sysfs_ops     = &gfs2_attr_ops,
 };
 
-static struct kset *gfs2_kset;
-
-/*
- * display struct lm_lockstruct fields
- */
-
-struct lockstruct_attr {
-       struct attribute attr;
-       ssize_t (*show)(struct gfs2_sbd *, char *);
-};
-
-#define LOCKSTRUCT_ATTR(name, fmt)                                          \
-static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf)                 \
-{                                                                           \
-       return snprintf(buf, PAGE_SIZE, fmt, sdp->sd_lockstruct.ls_##name); \
-}                                                                           \
-static struct lockstruct_attr lockstruct_attr_##name = __ATTR_RO(name)
-
-LOCKSTRUCT_ATTR(jid,      "%u\n");
-LOCKSTRUCT_ATTR(first,    "%u\n");
-
-static struct attribute *lockstruct_attrs[] = {
-       &lockstruct_attr_jid.attr,
-       &lockstruct_attr_first.attr,
-       NULL,
-};
 
 /*
  * lock_module. Originally from lock_dlm
@@ -359,34 +337,33 @@ static ssize_t first_done_show(struct gfs2_sbd *sdp, char *buf)
        return sprintf(buf, "%d\n", ls->ls_first_done);
 }
 
-static ssize_t recover_show(struct gfs2_sbd *sdp, char *buf)
-{
-       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
-       return sprintf(buf, "%d\n", ls->ls_recover_jid);
-}
-
-static void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid)
+static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
 {
+       unsigned jid;
        struct gfs2_jdesc *jd;
+       int rv;
+
+       rv = sscanf(buf, "%u", &jid);
+       if (rv != 1)
+               return -EINVAL;
 
+       rv = -ESHUTDOWN;
        spin_lock(&sdp->sd_jindex_spin);
+       if (test_bit(SDF_NORECOVERY, &sdp->sd_flags))
+               goto out;
+       rv = -EBUSY;
+       if (sdp->sd_jdesc->jd_jid == jid)
+               goto out;
+       rv = -ENOENT;
        list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
                if (jd->jd_jid != jid)
                        continue;
-               jd->jd_dirty = 1;
+               rv = slow_work_enqueue(&jd->jd_work);
                break;
        }
+out:
        spin_unlock(&sdp->sd_jindex_spin);
-}
-
-static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
-{
-       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
-       ls->ls_recover_jid = simple_strtol(buf, NULL, 0);
-       gfs2_jdesc_make_dirty(sdp, ls->ls_recover_jid);
-       if (sdp->sd_recoverd_process)
-               wake_up_process(sdp->sd_recoverd_process);
-       return len;
+       return rv ? rv : len;
 }
 
 static ssize_t recover_done_show(struct gfs2_sbd *sdp, char *buf)
@@ -401,31 +378,31 @@ static ssize_t recover_status_show(struct gfs2_sbd *sdp, char *buf)
        return sprintf(buf, "%d\n", ls->ls_recover_jid_status);
 }
 
-struct gdlm_attr {
-       struct attribute attr;
-       ssize_t (*show)(struct gfs2_sbd *sdp, char *);
-       ssize_t (*store)(struct gfs2_sbd *sdp, const char *, size_t);
-};
+static ssize_t jid_show(struct gfs2_sbd *sdp, char *buf)
+{
+       return sprintf(buf, "%u\n", sdp->sd_lockstruct.ls_jid);
+}
 
 #define GDLM_ATTR(_name,_mode,_show,_store) \
-static struct gdlm_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store)
-
-GDLM_ATTR(proto_name,     0444, proto_name_show,     NULL);
-GDLM_ATTR(block,          0644, block_show,          block_store);
-GDLM_ATTR(withdraw,       0644, withdraw_show,       withdraw_store);
-GDLM_ATTR(id,             0444, lkid_show,           NULL);
-GDLM_ATTR(first,          0444, lkfirst_show,        NULL);
-GDLM_ATTR(first_done,     0444, first_done_show,     NULL);
-GDLM_ATTR(recover,        0644, recover_show,        recover_store);
-GDLM_ATTR(recover_done,   0444, recover_done_show,   NULL);
-GDLM_ATTR(recover_status, 0444, recover_status_show, NULL);
+static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store)
+
+GDLM_ATTR(proto_name,     0444, proto_name_show,       NULL);
+GDLM_ATTR(block,          0644, block_show,            block_store);
+GDLM_ATTR(withdraw,       0644, withdraw_show,         withdraw_store);
+GDLM_ATTR(id,             0444, lkid_show,             NULL);
+GDLM_ATTR(jid,           0444, jid_show,               NULL);
+GDLM_ATTR(first,          0444, lkfirst_show,          NULL);
+GDLM_ATTR(first_done,     0444, first_done_show,       NULL);
+GDLM_ATTR(recover,        0200, NULL,                  recover_store);
+GDLM_ATTR(recover_done,   0444, recover_done_show,     NULL);
+GDLM_ATTR(recover_status, 0444, recover_status_show,   NULL);
 
 static struct attribute *lock_module_attrs[] = {
        &gdlm_attr_proto_name.attr,
        &gdlm_attr_block.attr,
        &gdlm_attr_withdraw.attr,
        &gdlm_attr_id.attr,
-       &lockstruct_attr_jid.attr,
+       &gdlm_attr_jid.attr,
        &gdlm_attr_first.attr,
        &gdlm_attr_first_done.attr,
        &gdlm_attr_recover.attr,
@@ -434,53 +411,6 @@ static struct attribute *lock_module_attrs[] = {
        NULL,
 };
 
-/*
- * display struct gfs2_args fields
- */
-
-struct args_attr {
-       struct attribute attr;
-       ssize_t (*show)(struct gfs2_sbd *, char *);
-};
-
-#define ARGS_ATTR(name, fmt)                                                \
-static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf)                 \
-{                                                                           \
-       return snprintf(buf, PAGE_SIZE, fmt, sdp->sd_args.ar_##name);       \
-}                                                                           \
-static struct args_attr args_attr_##name = __ATTR_RO(name)
-
-ARGS_ATTR(lockproto,       "%s\n");
-ARGS_ATTR(locktable,       "%s\n");
-ARGS_ATTR(hostdata,        "%s\n");
-ARGS_ATTR(spectator,       "%d\n");
-ARGS_ATTR(ignore_local_fs, "%d\n");
-ARGS_ATTR(localcaching,    "%d\n");
-ARGS_ATTR(localflocks,     "%d\n");
-ARGS_ATTR(debug,           "%d\n");
-ARGS_ATTR(upgrade,         "%d\n");
-ARGS_ATTR(posix_acl,       "%d\n");
-ARGS_ATTR(quota,           "%u\n");
-ARGS_ATTR(suiddir,         "%d\n");
-ARGS_ATTR(data,            "%d\n");
-
-static struct attribute *args_attrs[] = {
-       &args_attr_lockproto.attr,
-       &args_attr_locktable.attr,
-       &args_attr_hostdata.attr,
-       &args_attr_spectator.attr,
-       &args_attr_ignore_local_fs.attr,
-       &args_attr_localcaching.attr,
-       &args_attr_localflocks.attr,
-       &args_attr_debug.attr,
-       &args_attr_upgrade.attr,
-       &args_attr_posix_acl.attr,
-       &args_attr_quota.attr,
-       &args_attr_suiddir.attr,
-       &args_attr_data.attr,
-       NULL,
-};
-
 /*
  * get and set struct gfs2_tune fields
  */
@@ -531,14 +461,8 @@ static ssize_t tune_set(struct gfs2_sbd *sdp, unsigned int *field,
        return len;
 }
 
-struct tune_attr {
-       struct attribute attr;
-       ssize_t (*show)(struct gfs2_sbd *, char *);
-       ssize_t (*store)(struct gfs2_sbd *, const char *, size_t);
-};
-
 #define TUNE_ATTR_3(name, show, store)                                        \
-static struct tune_attr tune_attr_##name = __ATTR(name, 0644, show, store)
+static struct gfs2_attr tune_attr_##name = __ATTR(name, 0644, show, store)
 
 #define TUNE_ATTR_2(name, store)                                              \
 static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf)                   \
@@ -554,15 +478,6 @@ static ssize_t name##_store(struct gfs2_sbd *sdp, const char *buf, size_t len)\
 }                                                                             \
 TUNE_ATTR_2(name, name##_store)
 
-#define TUNE_ATTR_DAEMON(name, process)                                       \
-static ssize_t name##_store(struct gfs2_sbd *sdp, const char *buf, size_t len)\
-{                                                                             \
-       ssize_t r = tune_set(sdp, &sdp->sd_tune.gt_##name, 1, buf, len);      \
-       wake_up_process(sdp->sd_##process);                                   \
-       return r;                                                             \
-}                                                                             \
-TUNE_ATTR_2(name, name##_store)
-
 TUNE_ATTR(incore_log_blocks, 0);
 TUNE_ATTR(log_flush_secs, 0);
 TUNE_ATTR(quota_warn_period, 0);
@@ -574,8 +489,6 @@ TUNE_ATTR(new_files_jdata, 0);
 TUNE_ATTR(quota_simul_sync, 1);
 TUNE_ATTR(stall_secs, 1);
 TUNE_ATTR(statfs_quantum, 1);
-TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process);
-TUNE_ATTR_DAEMON(logd_secs, logd_process);
 TUNE_ATTR_3(quota_scale, quota_scale_show, quota_scale_store);
 
 static struct attribute *tune_attrs[] = {
@@ -589,23 +502,11 @@ static struct attribute *tune_attrs[] = {
        &tune_attr_quota_simul_sync.attr,
        &tune_attr_stall_secs.attr,
        &tune_attr_statfs_quantum.attr,
-       &tune_attr_recoverd_secs.attr,
-       &tune_attr_logd_secs.attr,
        &tune_attr_quota_scale.attr,
        &tune_attr_new_files_jdata.attr,
        NULL,
 };
 
-static struct attribute_group lockstruct_group = {
-       .name = "lockstruct",
-       .attrs = lockstruct_attrs,
-};
-
-static struct attribute_group args_group = {
-       .name = "args",
-       .attrs = args_attrs,
-};
-
 static struct attribute_group tune_group = {
        .name = "tune",
        .attrs = tune_attrs,
@@ -626,17 +527,9 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
        if (error)
                goto fail;
 
-       error = sysfs_create_group(&sdp->sd_kobj, &lockstruct_group);
-       if (error)
-               goto fail_reg;
-
-       error = sysfs_create_group(&sdp->sd_kobj, &args_group);
-       if (error)
-               goto fail_lockstruct;
-
        error = sysfs_create_group(&sdp->sd_kobj, &tune_group);
        if (error)
-               goto fail_args;
+               goto fail_reg;
 
        error = sysfs_create_group(&sdp->sd_kobj, &lock_module_group);
        if (error)
@@ -647,10 +540,6 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
 
 fail_tune:
        sysfs_remove_group(&sdp->sd_kobj, &tune_group);
-fail_args:
-       sysfs_remove_group(&sdp->sd_kobj, &args_group);
-fail_lockstruct:
-       sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
 fail_reg:
        kobject_put(&sdp->sd_kobj);
 fail:
@@ -661,8 +550,6 @@ fail:
 void gfs2_sys_fs_del(struct gfs2_sbd *sdp)
 {
        sysfs_remove_group(&sdp->sd_kobj, &tune_group);
-       sysfs_remove_group(&sdp->sd_kobj, &args_group);
-       sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
        sysfs_remove_group(&sdp->sd_kobj, &lock_module_group);
        kobject_put(&sdp->sd_kobj);
 }
index 053752d4b27f0c3dc52578c5066245e0fb793c69..4ef0e9fa3549bef52daffcc26a70635a1fd70950 100644 (file)
@@ -33,6 +33,9 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
        BUG_ON(current->journal_info);
        BUG_ON(blocks == 0 && revokes == 0);
 
+       if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
+               return -EROFS;
+
        tr = kzalloc(sizeof(struct gfs2_trans), GFP_NOFS);
        if (!tr)
                return -ENOMEM;
@@ -54,12 +57,6 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
        if (error)
                goto fail_holder_uninit;
 
-       if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
-               tr->tr_t_gh.gh_flags |= GL_NOCACHE;
-               error = -EROFS;
-               goto fail_gunlock;
-       }
-
        error = gfs2_log_reserve(sdp, tr->tr_reserved);
        if (error)
                goto fail_gunlock;
index c1462d43e7217de23f046852d9fd466af0617e65..941c8425c10b34493e9ad6fefef7fe54f451c84a 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/dnotify.h>
 #include <linux/statfs.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 
 #include <asm/uaccess.h>
 
@@ -986,6 +987,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag)
                        &hugetlbfs_file_operations);
        if (!file)
                goto out_dentry; /* inode is already attached */
+       ima_counts_get(file);
 
        return file;
 
index 82d9c42b8bac951f54fe0a09298eb90a0627f667..286f38dfc6c0748d90d471c0878e4d08e8f7ece5 100644 (file)
@@ -414,10 +414,6 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
        switch (cmd) {
        case FIBMAP:
                return ioctl_fibmap(filp, p);
-       case FS_IOC_FIEMAP:
-               return ioctl_fiemap(filp, arg);
-       case FIGETBSZ:
-               return put_user(inode->i_sb->s_blocksize, p);
        case FIONREAD:
                return put_user(i_size_read(inode) - filp->f_pos, p);
        }
@@ -557,6 +553,16 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
                error = ioctl_fsthaw(filp);
                break;
 
+       case FS_IOC_FIEMAP:
+               return ioctl_fiemap(filp, arg);
+
+       case FIGETBSZ:
+       {
+               struct inode *inode = filp->f_path.dentry->d_inode;
+               int __user *p = (int __user *)arg;
+               return put_user(inode->i_sb->s_blocksize, p);
+       }
+
        default:
                if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
                        error = file_ioctl(filp, cmd, arg);
index 58144102bf253b2244fee8fe44ce1a7c02cfbc79..62be7d294ec26eb71130692cc9187314141fd34d 100644 (file)
@@ -1781,7 +1781,7 @@ int jbd2_journal_wipe(journal_t *journal, int write)
  * Journal abort has very specific semantics, which we describe
  * for journal abort.
  *
- * Two internal function, which provide abort to te jbd layer
+ * Two internal functions, which provide abort to the jbd layer
  * itself are here.
  */
 
@@ -1879,7 +1879,7 @@ void jbd2_journal_abort(journal_t *journal, int errno)
  * int jbd2_journal_errno () - returns the journal's error state.
  * @journal: journal to examine.
  *
- * This is the errno numbet set with jbd2_journal_abort(), the last
+ * This is the errno number set with jbd2_journal_abort(), the last
  * time the journal was mounted - if the journal was stopped
  * without calling abort this will be 0.
  *
@@ -1903,7 +1903,7 @@ int jbd2_journal_errno(journal_t *journal)
  * int jbd2_journal_clear_err () - clears the journal's error state
  * @journal: journal to act on.
  *
- * An error must be cleared or Acked to take a FS out of readonly
+ * An error must be cleared or acked to take a FS out of readonly
  * mode.
  */
 int jbd2_journal_clear_err(journal_t *journal)
@@ -1923,7 +1923,7 @@ int jbd2_journal_clear_err(journal_t *journal)
  * void jbd2_journal_ack_err() - Ack journal err.
  * @journal: journal to act on.
  *
- * An error must be cleared or Acked to take a FS out of readonly
+ * An error must be cleared or acked to take a FS out of readonly
  * mode.
  */
 void jbd2_journal_ack_err(journal_t *journal)
index 680ba60863ffb2dee0f81ffbda6974c419c79668..42381bd6543b1abd5446961424234f6d83234f13 100644 (file)
@@ -379,7 +379,8 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages,
        struct buffer_head map_bh;
        unsigned long first_logical_block = 0;
 
-       clear_buffer_mapped(&map_bh);
+       map_bh.b_state = 0;
+       map_bh.b_size = 0;
        for (page_idx = 0; page_idx < nr_pages; page_idx++) {
                struct page *page = list_entry(pages->prev, struct page, lru);
 
@@ -412,7 +413,8 @@ int mpage_readpage(struct page *page, get_block_t get_block)
        struct buffer_head map_bh;
        unsigned long first_logical_block = 0;
 
-       clear_buffer_mapped(&map_bh);
+       map_bh.b_state = 0;
+       map_bh.b_size = 0;
        bio = do_mpage_readpage(bio, page, 1, &last_block_in_bio,
                        &map_bh, &first_logical_block, get_block);
        if (bio)
index 967c3db9272453e5cdd597d8f9fb50b4ceae0367..c82805d088e1d5c0bfcd0229fc0cd7bd0c3a69db 100644 (file)
@@ -853,7 +853,8 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
                        err = inode_permission(nd->path.dentry->d_inode,
                                               MAY_EXEC);
                if (!err)
-                       err = ima_path_check(&nd->path, MAY_EXEC);
+                       err = ima_path_check(&nd->path, MAY_EXEC,
+                                            IMA_COUNT_UPDATE);
                if (err)
                        break;
 
@@ -1515,7 +1516,8 @@ int may_open(struct path *path, int acc_mode, int flag)
                return error;
 
        error = ima_path_check(path,
-                              acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC));
+                              acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC),
+                              IMA_COUNT_UPDATE);
        if (error)
                return error;
        /*
index b660435978d288de89bf42070b3a6e83399b2356..bd584bcf1d9f9690b1304794472c3dfdf4a88f79 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/security.h>
 #endif /* CONFIG_NFSD_V4 */
 #include <linux/jhash.h>
+#include <linux/ima.h>
 
 #include <asm/uaccess.h>
 
@@ -735,6 +736,8 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
                            flags, cred);
        if (IS_ERR(*filp))
                host_err = PTR_ERR(*filp);
+       else
+               ima_counts_get(*filp);
 out_nfserr:
        err = nfserrno(host_err);
 out:
@@ -2024,6 +2027,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
                                        struct dentry *dentry, int acc)
 {
        struct inode    *inode = dentry->d_inode;
+       struct path     path;
        int             err;
 
        if (acc == NFSD_MAY_NOP)
@@ -2096,7 +2100,17 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
        if (err == -EACCES && S_ISREG(inode->i_mode) &&
            acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE))
                err = inode_permission(inode, MAY_EXEC);
+       if (err)
+               goto nfsd_out;
 
+       /* Do integrity (permission) checking now, but defer incrementing
+        * IMA counts to the actual file open.
+        */
+       path.mnt = exp->ex_path.mnt;
+       path.dentry = dentry;
+       err = ima_path_check(&path, acc & (MAY_READ | MAY_WRITE | MAY_EXEC),
+                            IMA_COUNT_LEAVE);
+nfsd_out:
        return err? nfserrno(err) : 0;
 }
 
index 7f65b3be4aa91dba3b923b3fd47e25ee3f7db68a..a91f15b8673c3c1ed8728ab5db8bd479e1ea6a70 100644 (file)
@@ -515,7 +515,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
 
        blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
        if (sb->s_blocksize != blocksize) {
-               int hw_blocksize = bdev_hardsect_size(sb->s_bdev);
+               int hw_blocksize = bdev_logical_block_size(sb->s_bdev);
 
                if (blocksize < hw_blocksize) {
                        printk(KERN_ERR
index f76951dcd4a6e984f2469b06df80dd0aa9e96891..6aa7c4713536636b08df670c9efb030640730489 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/spinlock.h>
-#include <linux/blkdev.h>      /* For bdev_hardsect_size(). */
+#include <linux/blkdev.h>      /* For bdev_logical_block_size(). */
 #include <linux/backing-dev.h>
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
@@ -2785,13 +2785,13 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
                goto err_out_now;
 
        /* We support sector sizes up to the PAGE_CACHE_SIZE. */
-       if (bdev_hardsect_size(sb->s_bdev) > PAGE_CACHE_SIZE) {
+       if (bdev_logical_block_size(sb->s_bdev) > PAGE_CACHE_SIZE) {
                if (!silent)
                        ntfs_error(sb, "Device has unsupported sector size "
                                        "(%i).  The maximum supported sector "
                                        "size on this architecture is %lu "
                                        "bytes.",
-                                       bdev_hardsect_size(sb->s_bdev),
+                                       bdev_logical_block_size(sb->s_bdev),
                                        PAGE_CACHE_SIZE);
                goto err_out_now;
        }
index 4f85eceab376015596adbafae5b9eb774211e2b1..09cc25d04611bfac57adfd422ba519a1c7a5664b 100644 (file)
@@ -1371,7 +1371,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
 
        bdevname(reg->hr_bdev, reg->hr_dev_name);
 
-       sectsize = bdev_hardsect_size(reg->hr_bdev);
+       sectsize = bdev_logical_block_size(reg->hr_bdev);
        if (sectsize != reg->hr_block_bytes) {
                mlog(ML_ERROR,
                     "blocksize %u incorrect for device, expected %d",
index 79ff8d9d37e0844252130272309cd5853b04445e..5c6163f550393a1e0a50f9f513d1ad3f185a6ab2 100644 (file)
@@ -713,7 +713,7 @@ static int ocfs2_sb_probe(struct super_block *sb,
        *bh = NULL;
 
        /* may be > 512 */
-       *sector_size = bdev_hardsect_size(sb->s_bdev);
+       *sector_size = bdev_logical_block_size(sb->s_bdev);
        if (*sector_size > OCFS2_MAX_BLOCKSIZE) {
                mlog(ML_ERROR, "Hardware sector size too large: %d (max=%d)\n",
                     *sector_size, OCFS2_MAX_BLOCKSIZE);
index 99e33ef40be477902faf9b02f6cd8bfc5e20293a..0af36085eb28b21498036ce42f5fb682153b7baa 100644 (file)
@@ -219,6 +219,13 @@ ssize_t part_size_show(struct device *dev,
        return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects);
 }
 
+ssize_t part_alignment_offset_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct hd_struct *p = dev_to_part(dev);
+       return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset);
+}
+
 ssize_t part_stat_show(struct device *dev,
                       struct device_attribute *attr, char *buf)
 {
@@ -272,6 +279,7 @@ ssize_t part_fail_store(struct device *dev,
 static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL);
 static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL);
 static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
+static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL);
 static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
 #ifdef CONFIG_FAIL_MAKE_REQUEST
 static struct device_attribute dev_attr_fail =
@@ -282,6 +290,7 @@ static struct attribute *part_attrs[] = {
        &dev_attr_partition.attr,
        &dev_attr_start.attr,
        &dev_attr_size.attr,
+       &dev_attr_alignment_offset.attr,
        &dev_attr_stat.attr,
 #ifdef CONFIG_FAIL_MAKE_REQUEST
        &dev_attr_fail.attr,
@@ -383,6 +392,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
        pdev = part_to_dev(p);
 
        p->start_sect = start;
+       p->alignment_offset = queue_sector_alignment_offset(disk->queue, start);
        p->nr_sects = len;
        p->partno = partno;
        p->policy = get_disk_ro(disk);
index 46297683cd34bbaf4b0396172159ab21cd575baa..fc71aab084603749abc8138ee860c2f17faa05fa 100644 (file)
@@ -76,7 +76,7 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
        Sector sect;
 
        res = 0;
-       blocksize = bdev_hardsect_size(bdev);
+       blocksize = bdev_logical_block_size(bdev);
        if (blocksize <= 0)
                goto out_exit;
        i_size = i_size_read(bdev->bd_inode);
index 796511886f285804060ddd62390012751da14685..0028d2ef0662b0f01fd21b7685754d9939ebbd51 100644 (file)
@@ -110,7 +110,7 @@ parse_extended(struct parsed_partitions *state, struct block_device *bdev,
        Sector sect;
        unsigned char *data;
        u32 this_sector, this_size;
-       int sector_size = bdev_hardsect_size(bdev) / 512;
+       int sector_size = bdev_logical_block_size(bdev) / 512;
        int loopct = 0;         /* number of links followed
                                   without finding a data partition */
        int i;
@@ -415,7 +415,7 @@ static struct {
  
 int msdos_partition(struct parsed_partitions *state, struct block_device *bdev)
 {
-       int sector_size = bdev_hardsect_size(bdev) / 512;
+       int sector_size = bdev_logical_block_size(bdev) / 512;
        Sector sect;
        unsigned char *data;
        struct partition *p;
index 13414ec45b8d5b42012d8c5fbd56d54df5a96749..f7dd21ad85a61937666eddf0ccbff66e11e6c3fd 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -302,6 +302,20 @@ int generic_pipe_buf_confirm(struct pipe_inode_info *info,
        return 0;
 }
 
+/**
+ * generic_pipe_buf_release - put a reference to a &struct pipe_buffer
+ * @pipe:      the pipe that the buffer belongs to
+ * @buf:       the buffer to put a reference to
+ *
+ * Description:
+ *     This function releases a reference to @buf.
+ */
+void generic_pipe_buf_release(struct pipe_inode_info *pipe,
+                             struct pipe_buffer *buf)
+{
+       page_cache_release(buf->page);
+}
+
 static const struct pipe_buf_operations anon_pipe_buf_ops = {
        .can_merge = 1,
        .map = generic_pipe_buf_map,
index 3326bbf9ab95222dbc2466a846650c7935e58cf5..1539e630c47d524b1df251236e638dbb1e8d279b 100644 (file)
@@ -2128,9 +2128,15 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
        if (copy_from_user(page, buf, count))
                goto out_free;
 
+       /* Guard against adverse ptrace interaction */
+       length = mutex_lock_interruptible(&task->cred_guard_mutex);
+       if (length < 0)
+               goto out_free;
+
        length = security_setprocattr(task,
                                      (char*)file->f_path.dentry->d_name.name,
                                      (void*)page, count);
+       mutex_unlock(&task->cred_guard_mutex);
 out_free:
        free_page((unsigned long) page);
 out:
index 9bca39cf99eeb56d6c32c4f0f9f4c49073683f19..1afa4dd4cae24167a0c4e3f47137a13cf8a6d199 100644 (file)
 
 static int loadavg_proc_show(struct seq_file *m, void *v)
 {
-       int a, b, c;
-       unsigned long seq;
+       unsigned long avnrun[3];
 
-       do {
-               seq = read_seqbegin(&xtime_lock);
-               a = avenrun[0] + (FIXED_1/200);
-               b = avenrun[1] + (FIXED_1/200);
-               c = avenrun[2] + (FIXED_1/200);
-       } while (read_seqretry(&xtime_lock, seq));
+       get_avenrun(avnrun, FIXED_1/200, 0);
 
-       seq_printf(m, "%d.%02d %d.%02d %d.%02d %ld/%d %d\n",
-               LOAD_INT(a), LOAD_FRAC(a),
-               LOAD_INT(b), LOAD_FRAC(b),
-               LOAD_INT(c), LOAD_FRAC(c),
+       seq_printf(m, "%lu.%02lu %lu.%02lu %lu.%02lu %ld/%d %d\n",
+               LOAD_INT(avnrun[0]), LOAD_FRAC(avnrun[0]),
+               LOAD_INT(avnrun[1]), LOAD_FRAC(avnrun[1]),
+               LOAD_INT(avnrun[2]), LOAD_FRAC(avnrun[2]),
                nr_running(), nr_threads,
                task_active_pid_ns(current)->last_pid);
        return 0;
index 9d1e76bb9ee147b8236630ba953a53873b1847d4..6c8c55dec2bcd6b2759f9698abab5b663258cc4b 100644 (file)
@@ -805,12 +805,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
                goto out;
        if (!(in_file->f_mode & FMODE_READ))
                goto fput_in;
-       retval = -EINVAL;
-       in_inode = in_file->f_path.dentry->d_inode;
-       if (!in_inode)
-               goto fput_in;
-       if (!in_file->f_op || !in_file->f_op->splice_read)
-               goto fput_in;
        retval = -ESPIPE;
        if (!ppos)
                ppos = &in_file->f_pos;
@@ -834,6 +828,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
        retval = -EINVAL;
        if (!out_file->f_op || !out_file->f_op->sendpage)
                goto fput_out;
+       in_inode = in_file->f_path.dentry->d_inode;
        out_inode = out_file->f_path.dentry->d_inode;
        retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count);
        if (retval < 0)
index 666953d59a35c77670514b916aea7515fe612951..73766d24f97b9d41f48ba2cadf36d4cd7ae3d60b 100644 (file)
@@ -507,9 +507,131 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
 
        return ret;
 }
-
 EXPORT_SYMBOL(generic_file_splice_read);
 
+static const struct pipe_buf_operations default_pipe_buf_ops = {
+       .can_merge = 0,
+       .map = generic_pipe_buf_map,
+       .unmap = generic_pipe_buf_unmap,
+       .confirm = generic_pipe_buf_confirm,
+       .release = generic_pipe_buf_release,
+       .steal = generic_pipe_buf_steal,
+       .get = generic_pipe_buf_get,
+};
+
+static ssize_t kernel_readv(struct file *file, const struct iovec *vec,
+                           unsigned long vlen, loff_t offset)
+{
+       mm_segment_t old_fs;
+       loff_t pos = offset;
+       ssize_t res;
+
+       old_fs = get_fs();
+       set_fs(get_ds());
+       /* The cast to a user pointer is valid due to the set_fs() */
+       res = vfs_readv(file, (const struct iovec __user *)vec, vlen, &pos);
+       set_fs(old_fs);
+
+       return res;
+}
+
+static ssize_t kernel_write(struct file *file, const char *buf, size_t count,
+                           loff_t pos)
+{
+       mm_segment_t old_fs;
+       ssize_t res;
+
+       old_fs = get_fs();
+       set_fs(get_ds());
+       /* The cast to a user pointer is valid due to the set_fs() */
+       res = vfs_write(file, (const char __user *)buf, count, &pos);
+       set_fs(old_fs);
+
+       return res;
+}
+
+ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
+                                struct pipe_inode_info *pipe, size_t len,
+                                unsigned int flags)
+{
+       unsigned int nr_pages;
+       unsigned int nr_freed;
+       size_t offset;
+       struct page *pages[PIPE_BUFFERS];
+       struct partial_page partial[PIPE_BUFFERS];
+       struct iovec vec[PIPE_BUFFERS];
+       pgoff_t index;
+       ssize_t res;
+       size_t this_len;
+       int error;
+       int i;
+       struct splice_pipe_desc spd = {
+               .pages = pages,
+               .partial = partial,
+               .flags = flags,
+               .ops = &default_pipe_buf_ops,
+               .spd_release = spd_release_page,
+       };
+
+       index = *ppos >> PAGE_CACHE_SHIFT;
+       offset = *ppos & ~PAGE_CACHE_MASK;
+       nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+
+       for (i = 0; i < nr_pages && i < PIPE_BUFFERS && len; i++) {
+               struct page *page;
+
+               page = alloc_page(GFP_USER);
+               error = -ENOMEM;
+               if (!page)
+                       goto err;
+
+               this_len = min_t(size_t, len, PAGE_CACHE_SIZE - offset);
+               vec[i].iov_base = (void __user *) page_address(page);
+               vec[i].iov_len = this_len;
+               pages[i] = page;
+               spd.nr_pages++;
+               len -= this_len;
+               offset = 0;
+       }
+
+       res = kernel_readv(in, vec, spd.nr_pages, *ppos);
+       if (res < 0) {
+               error = res;
+               goto err;
+       }
+
+       error = 0;
+       if (!res)
+               goto err;
+
+       nr_freed = 0;
+       for (i = 0; i < spd.nr_pages; i++) {
+               this_len = min_t(size_t, vec[i].iov_len, res);
+               partial[i].offset = 0;
+               partial[i].len = this_len;
+               if (!this_len) {
+                       __free_page(pages[i]);
+                       pages[i] = NULL;
+                       nr_freed++;
+               }
+               res -= this_len;
+       }
+       spd.nr_pages -= nr_freed;
+
+       res = splice_to_pipe(pipe, &spd);
+       if (res > 0)
+               *ppos += res;
+
+       return res;
+
+err:
+       for (i = 0; i < spd.nr_pages; i++)
+               __free_page(pages[i]);
+
+       return error;
+}
+EXPORT_SYMBOL(default_file_splice_read);
+
 /*
  * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos'
  * using sendpage(). Return the number of bytes sent.
@@ -881,6 +1003,36 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
 
 EXPORT_SYMBOL(generic_file_splice_write);
 
+static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
+                         struct splice_desc *sd)
+{
+       int ret;
+       void *data;
+
+       ret = buf->ops->confirm(pipe, buf);
+       if (ret)
+               return ret;
+
+       data = buf->ops->map(pipe, buf, 0);
+       ret = kernel_write(sd->u.file, data + buf->offset, sd->len, sd->pos);
+       buf->ops->unmap(pipe, buf, data);
+
+       return ret;
+}
+
+static ssize_t default_file_splice_write(struct pipe_inode_info *pipe,
+                                        struct file *out, loff_t *ppos,
+                                        size_t len, unsigned int flags)
+{
+       ssize_t ret;
+
+       ret = splice_from_pipe(pipe, out, ppos, len, flags, write_pipe_buf);
+       if (ret > 0)
+               *ppos += ret;
+
+       return ret;
+}
+
 /**
  * generic_splice_sendpage - splice data from a pipe to a socket
  * @pipe:      pipe to splice from
@@ -908,11 +1060,10 @@ EXPORT_SYMBOL(generic_splice_sendpage);
 static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
                           loff_t *ppos, size_t len, unsigned int flags)
 {
+       ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
+                               loff_t *, size_t, unsigned int);
        int ret;
 
-       if (unlikely(!out->f_op || !out->f_op->splice_write))
-               return -EINVAL;
-
        if (unlikely(!(out->f_mode & FMODE_WRITE)))
                return -EBADF;
 
@@ -923,7 +1074,11 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
        if (unlikely(ret < 0))
                return ret;
 
-       return out->f_op->splice_write(pipe, out, ppos, len, flags);
+       splice_write = out->f_op->splice_write;
+       if (!splice_write)
+               splice_write = default_file_splice_write;
+
+       return splice_write(pipe, out, ppos, len, flags);
 }
 
 /*
@@ -933,11 +1088,10 @@ static long do_splice_to(struct file *in, loff_t *ppos,
                         struct pipe_inode_info *pipe, size_t len,
                         unsigned int flags)
 {
+       ssize_t (*splice_read)(struct file *, loff_t *,
+                              struct pipe_inode_info *, size_t, unsigned int);
        int ret;
 
-       if (unlikely(!in->f_op || !in->f_op->splice_read))
-               return -EINVAL;
-
        if (unlikely(!(in->f_mode & FMODE_READ)))
                return -EBADF;
 
@@ -945,7 +1099,11 @@ static long do_splice_to(struct file *in, loff_t *ppos,
        if (unlikely(ret < 0))
                return ret;
 
-       return in->f_op->splice_read(in, ppos, pipe, len, flags);
+       splice_read = in->f_op->splice_read;
+       if (!splice_read)
+               splice_read = default_file_splice_read;
+
+       return splice_read(in, ppos, pipe, len, flags);
 }
 
 /**
@@ -1112,6 +1270,9 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
        return ret;
 }
 
+static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
+                              struct pipe_inode_info *opipe,
+                              size_t len, unsigned int flags);
 /*
  * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same
  * location, so checking ->i_pipe is not enough to verify that this is a
@@ -1132,12 +1293,32 @@ static long do_splice(struct file *in, loff_t __user *off_in,
                      struct file *out, loff_t __user *off_out,
                      size_t len, unsigned int flags)
 {
-       struct pipe_inode_info *pipe;
+       struct pipe_inode_info *ipipe;
+       struct pipe_inode_info *opipe;
        loff_t offset, *off;
        long ret;
 
-       pipe = pipe_info(in->f_path.dentry->d_inode);
-       if (pipe) {
+       ipipe = pipe_info(in->f_path.dentry->d_inode);
+       opipe = pipe_info(out->f_path.dentry->d_inode);
+
+       if (ipipe && opipe) {
+               if (off_in || off_out)
+                       return -ESPIPE;
+
+               if (!(in->f_mode & FMODE_READ))
+                       return -EBADF;
+
+               if (!(out->f_mode & FMODE_WRITE))
+                       return -EBADF;
+
+               /* Splicing to self would be fun, but... */
+               if (ipipe == opipe)
+                       return -EINVAL;
+
+               return splice_pipe_to_pipe(ipipe, opipe, len, flags);
+       }
+
+       if (ipipe) {
                if (off_in)
                        return -ESPIPE;
                if (off_out) {
@@ -1149,7 +1330,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
                } else
                        off = &out->f_pos;
 
-               ret = do_splice_from(pipe, out, off, len, flags);
+               ret = do_splice_from(ipipe, out, off, len, flags);
 
                if (off_out && copy_to_user(off_out, off, sizeof(loff_t)))
                        ret = -EFAULT;
@@ -1157,8 +1338,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
                return ret;
        }
 
-       pipe = pipe_info(out->f_path.dentry->d_inode);
-       if (pipe) {
+       if (opipe) {
                if (off_out)
                        return -ESPIPE;
                if (off_in) {
@@ -1170,7 +1350,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
                } else
                        off = &in->f_pos;
 
-               ret = do_splice_to(in, off, pipe, len, flags);
+               ret = do_splice_to(in, off, opipe, len, flags);
 
                if (off_in && copy_to_user(off_in, off, sizeof(loff_t)))
                        ret = -EFAULT;
@@ -1511,7 +1691,7 @@ SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in,
  * Make sure there's data to read. Wait for input if we can, otherwise
  * return an appropriate error.
  */
-static int link_ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
+static int ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
 {
        int ret;
 
@@ -1549,7 +1729,7 @@ static int link_ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
  * Make sure there's writeable room. Wait for room if we can, otherwise
  * return an appropriate error.
  */
-static int link_opipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
+static int opipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
 {
        int ret;
 
@@ -1586,6 +1766,124 @@ static int link_opipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
        return ret;
 }
 
+/*
+ * Splice contents of ipipe to opipe.
+ */
+static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
+                              struct pipe_inode_info *opipe,
+                              size_t len, unsigned int flags)
+{
+       struct pipe_buffer *ibuf, *obuf;
+       int ret = 0, nbuf;
+       bool input_wakeup = false;
+
+
+retry:
+       ret = ipipe_prep(ipipe, flags);
+       if (ret)
+               return ret;
+
+       ret = opipe_prep(opipe, flags);
+       if (ret)
+               return ret;
+
+       /*
+        * Potential ABBA deadlock, work around it by ordering lock
+        * grabbing by pipe info address. Otherwise two different processes
+        * could deadlock (one doing tee from A -> B, the other from B -> A).
+        */
+       pipe_double_lock(ipipe, opipe);
+
+       do {
+               if (!opipe->readers) {
+                       send_sig(SIGPIPE, current, 0);
+                       if (!ret)
+                               ret = -EPIPE;
+                       break;
+               }
+
+               if (!ipipe->nrbufs && !ipipe->writers)
+                       break;
+
+               /*
+                * Cannot make any progress, because either the input
+                * pipe is empty or the output pipe is full.
+                */
+               if (!ipipe->nrbufs || opipe->nrbufs >= PIPE_BUFFERS) {
+                       /* Already processed some buffers, break */
+                       if (ret)
+                               break;
+
+                       if (flags & SPLICE_F_NONBLOCK) {
+                               ret = -EAGAIN;
+                               break;
+                       }
+
+                       /*
+                        * We raced with another reader/writer and haven't
+                        * managed to process any buffers.  A zero return
+                        * value means EOF, so retry instead.
+                        */
+                       pipe_unlock(ipipe);
+                       pipe_unlock(opipe);
+                       goto retry;
+               }
+
+               ibuf = ipipe->bufs + ipipe->curbuf;
+               nbuf = (opipe->curbuf + opipe->nrbufs) % PIPE_BUFFERS;
+               obuf = opipe->bufs + nbuf;
+
+               if (len >= ibuf->len) {
+                       /*
+                        * Simply move the whole buffer from ipipe to opipe
+                        */
+                       *obuf = *ibuf;
+                       ibuf->ops = NULL;
+                       opipe->nrbufs++;
+                       ipipe->curbuf = (ipipe->curbuf + 1) % PIPE_BUFFERS;
+                       ipipe->nrbufs--;
+                       input_wakeup = true;
+               } else {
+                       /*
+                        * Get a reference to this pipe buffer,
+                        * so we can copy the contents over.
+                        */
+                       ibuf->ops->get(ipipe, ibuf);
+                       *obuf = *ibuf;
+
+                       /*
+                        * Don't inherit the gift flag, we need to
+                        * prevent multiple steals of this page.
+                        */
+                       obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
+
+                       obuf->len = len;
+                       opipe->nrbufs++;
+                       ibuf->offset += obuf->len;
+                       ibuf->len -= obuf->len;
+               }
+               ret += obuf->len;
+               len -= obuf->len;
+       } while (len);
+
+       pipe_unlock(ipipe);
+       pipe_unlock(opipe);
+
+       /*
+        * If we put data in the output pipe, wakeup any potential readers.
+        */
+       if (ret > 0) {
+               smp_mb();
+               if (waitqueue_active(&opipe->wait))
+                       wake_up_interruptible(&opipe->wait);
+               kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN);
+       }
+       if (input_wakeup)
+               wakeup_pipe_writers(ipipe);
+
+       return ret;
+}
+
 /*
  * Link contents of ipipe to opipe.
  */
@@ -1690,9 +1988,9 @@ static long do_tee(struct file *in, struct file *out, size_t len,
                 * Keep going, unless we encounter an error. The ipipe/opipe
                 * ordering doesn't really matter.
                 */
-               ret = link_ipipe_prep(ipipe, flags);
+               ret = ipipe_prep(ipipe, flags);
                if (!ret) {
-                       ret = link_opipe_prep(opipe, flags);
+                       ret = opipe_prep(opipe, flags);
                        if (!ret)
                                ret = link_pipe(ipipe, opipe, len, flags);
                }
index 72348cc855a45dd25126aaba8557772e0d4b491d..0ba44107d8f109af092106d6663e0a06df9de219 100644 (file)
@@ -1915,7 +1915,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        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);
+               uopt.blocksize = bdev_logical_block_size(sb->s_bdev);
                ret = udf_load_vrs(sb, &uopt, silent, &fileset);
                if (!ret && uopt.blocksize != UDF_DEFAULT_BLOCKSIZE) {
                        if (!silent)
index e28800a9f2b53890a1357a5db5d44da4943337f9..1418b916fc2755306cca61e60c734154d543c82f 100644 (file)
@@ -1501,7 +1501,7 @@ xfs_setsize_buftarg_early(
        struct block_device     *bdev)
 {
        return xfs_setsize_buftarg_flags(btp,
-                       PAGE_CACHE_SIZE, bdev_hardsect_size(bdev), 0);
+                       PAGE_CACHE_SIZE, bdev_logical_block_size(bdev), 0);
 }
 
 int
index d8c3e3cbf41603eb983e5922da3ee796c7fece84..fe36accd43283b77f372adcc2c9f815a7910a233 100644 (file)
@@ -8,3 +8,4 @@ header-y += mtd/
 header-y += rdma/
 header-y += video/
 header-y += drm/
+header-y += xen/
index 8e6d0ca70aba987b4663db6e512d79236400f183..e410f602cab1b31fdd71681708d17049181026d5 100644 (file)
@@ -280,17 +280,18 @@ static inline void ptep_modify_prot_commit(struct mm_struct *mm,
 #endif
 
 /*
- * A facility to provide batching of the reload of page tables with the
- * actual context switch code for paravirtualized guests.  By convention,
- * only one of the lazy modes (CPU, MMU) should be active at any given
- * time, entry should never be nested, and entry and exits should always
- * be paired.  This is for sanity of maintaining and reasoning about the
- * kernel code.
+ * A facility to provide batching of the reload of page tables and
+ * other process state with the actual context switch code for
+ * paravirtualized guests.  By convention, only one of the batched
+ * update (lazy) modes (CPU, MMU) should be active at any given time,
+ * entry should never be nested, and entry and exits should always be
+ * paired.  This is for sanity of maintaining and reasoning about the
+ * kernel code.  In this case, the exit (end of the context switch) is
+ * in architecture-specific code, and so doesn't need a generic
+ * definition.
  */
-#ifndef __HAVE_ARCH_ENTER_LAZY_CPU_MODE
-#define arch_enter_lazy_cpu_mode()     do {} while (0)
-#define arch_leave_lazy_cpu_mode()     do {} while (0)
-#define arch_flush_lazy_cpu_mode()     do {} while (0)
+#ifndef __HAVE_ARCH_START_CONTEXT_SWITCH
+#define arch_start_context_switch(prev)        do {} while (0)
 #endif
 
 #ifndef __HAVE_PFNMAP_TRACKING
index 89853bcd27a658ac0aef934c61ba723057933457..f1736ca7922cb0022244087119f73a70e85f8b23 100644 (file)
@@ -63,7 +63,7 @@
 #define BRANCH_PROFILE()
 #endif
 
-#ifdef CONFIG_EVENT_TRACER
+#ifdef CONFIG_EVENT_TRACING
 #define FTRACE_EVENTS()        VMLINUX_SYMBOL(__start_ftrace_events) = .;      \
                        *(_ftrace_events)                               \
                        VMLINUX_SYMBOL(__stop_ftrace_events) = .;
index 88be890ee3c7e402cfd398e5113d2f78bb29338b..51b4b0a5ce8cf00b00fd849ee26e0e7bc504a795 100644 (file)
@@ -119,7 +119,7 @@ extern int pci_mmcfg_config_num;
 extern int sbf_port;
 extern unsigned long acpi_realmode_flags;
 
-int acpi_register_gsi (u32 gsi, int triggering, int polarity);
+int acpi_register_gsi (struct device *dev, u32 gsi, int triggering, int polarity);
 int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
 
 #ifdef CONFIG_X86_IO_APIC
index 7b214fd672a2d923e56d8263d8c183d7dcf98b0e..12737be58601108f81f486fcdfac99c4875d8fb5 100644 (file)
@@ -218,12 +218,12 @@ struct bio {
 #define bio_sectors(bio)       ((bio)->bi_size >> 9)
 #define bio_empty_barrier(bio) (bio_barrier(bio) && !bio_has_data(bio) && !bio_discard(bio))
 
-static inline unsigned int bio_cur_sectors(struct bio *bio)
+static inline unsigned int bio_cur_bytes(struct bio *bio)
 {
        if (bio->bi_vcnt)
-               return bio_iovec(bio)->bv_len >> 9;
+               return bio_iovec(bio)->bv_len;
        else /* dataless requests such as discard */
-               return bio->bi_size >> 9;
+               return bio->bi_size;
 }
 
 static inline void *bio_data(struct bio *bio)
@@ -279,7 +279,7 @@ static inline int bio_has_allocated_vec(struct bio *bio)
 #define __BIO_SEG_BOUNDARY(addr1, addr2, mask) \
        (((addr1) | (mask)) == (((addr2) - 1) | (mask)))
 #define BIOVEC_SEG_BOUNDARY(q, b1, b2) \
-       __BIO_SEG_BOUNDARY(bvec_to_phys((b1)), bvec_to_phys((b2)) + (b2)->bv_len, (q)->seg_boundary_mask)
+       __BIO_SEG_BOUNDARY(bvec_to_phys((b1)), bvec_to_phys((b2)) + (b2)->bv_len, queue_segment_boundary((q)))
 #define BIO_SEG_BOUNDARY(q, b1, b2) \
        BIOVEC_SEG_BOUNDARY((q), __BVEC_END((b1)), __BVEC_START((b2)))
 
@@ -506,7 +506,7 @@ static inline int bio_has_data(struct bio *bio)
 }
 
 /*
- * BIO list managment for use by remapping drivers (e.g. DM or MD).
+ * BIO list management for use by remapping drivers (e.g. DM or MD) and loop.
  *
  * A bio_list anchors a singly-linked list of bios chained through the bi_next
  * member of the bio.  The bio_list also caches the last list member to allow
index b4f71f1a4af72bd7c68c6f6fe707f43e6a50888f..ebdfde8fe556166f19a81a59736cdb3b9aacaf6f 100644 (file)
@@ -166,19 +166,9 @@ struct request {
        enum rq_cmd_type_bits cmd_type;
        unsigned long atomic_flags;
 
-       /* Maintain bio traversal state for part by part I/O submission.
-        * hard_* are block layer internals, no driver should touch them!
-        */
-
-       sector_t sector;                /* next sector to submit */
-       sector_t hard_sector;           /* next sector to complete */
-       unsigned long nr_sectors;       /* no. of sectors left to submit */
-       unsigned long hard_nr_sectors;  /* no. of sectors left to complete */
-       /* no. of sectors left to submit in the current segment */
-       unsigned int current_nr_sectors;
-
-       /* no. of sectors left to complete in the current segment */
-       unsigned int hard_cur_sectors;
+       /* the following two fields are internal, NEVER access directly */
+       sector_t __sector;              /* sector cursor */
+       unsigned int __data_len;        /* total data len */
 
        struct bio *bio;
        struct bio *biotail;
@@ -211,8 +201,8 @@ struct request {
 
        unsigned short ioprio;
 
-       void *special;
-       char *buffer;
+       void *special;          /* opaque pointer available for LLD use */
+       char *buffer;           /* kaddr of the current segment if available */
 
        int tag;
        int errors;
@@ -226,10 +216,9 @@ struct request {
        unsigned char __cmd[BLK_MAX_CDB];
        unsigned char *cmd;
 
-       unsigned int data_len;
        unsigned int extra_len; /* length of alignment and padding */
        unsigned int sense_len;
-       void *data;
+       unsigned int resid_len; /* residual count */
        void *sense;
 
        unsigned long deadline;
@@ -318,6 +307,26 @@ struct blk_cmd_filter {
        struct kobject kobj;
 };
 
+struct queue_limits {
+       unsigned long           bounce_pfn;
+       unsigned long           seg_boundary_mask;
+
+       unsigned int            max_hw_sectors;
+       unsigned int            max_sectors;
+       unsigned int            max_segment_size;
+       unsigned int            physical_block_size;
+       unsigned int            alignment_offset;
+       unsigned int            io_min;
+       unsigned int            io_opt;
+
+       unsigned short          logical_block_size;
+       unsigned short          max_hw_segments;
+       unsigned short          max_phys_segments;
+
+       unsigned char           misaligned;
+       unsigned char           no_cluster;
+};
+
 struct request_queue
 {
        /*
@@ -369,7 +378,6 @@ struct request_queue
        /*
         * queue needs bounce pages for pages above this limit
         */
-       unsigned long           bounce_pfn;
        gfp_t                   bounce_gfp;
 
        /*
@@ -398,14 +406,6 @@ struct request_queue
        unsigned int            nr_congestion_off;
        unsigned int            nr_batching;
 
-       unsigned int            max_sectors;
-       unsigned int            max_hw_sectors;
-       unsigned short          max_phys_segments;
-       unsigned short          max_hw_segments;
-       unsigned short          hardsect_size;
-       unsigned int            max_segment_size;
-
-       unsigned long           seg_boundary_mask;
        void                    *dma_drain_buffer;
        unsigned int            dma_drain_size;
        unsigned int            dma_pad_mask;
@@ -415,12 +415,14 @@ struct request_queue
        struct list_head        tag_busy_list;
 
        unsigned int            nr_sorted;
-       unsigned int            in_flight;
+       unsigned int            in_flight[2];
 
        unsigned int            rq_timeout;
        struct timer_list       timeout;
        struct list_head        timeout_list;
 
+       struct queue_limits     limits;
+
        /*
         * sg stuff
         */
@@ -522,6 +524,11 @@ static inline void queue_flag_clear_unlocked(unsigned int flag,
        __clear_bit(flag, &q->queue_flags);
 }
 
+static inline int queue_in_flight(struct request_queue *q)
+{
+       return q->in_flight[0] + q->in_flight[1];
+}
+
 static inline void queue_flag_clear(unsigned int flag, struct request_queue *q)
 {
        WARN_ON_ONCE(!queue_is_locked(q));
@@ -752,10 +759,17 @@ extern void blk_rq_init(struct request_queue *q, struct request *rq);
 extern void blk_put_request(struct request *);
 extern void __blk_put_request(struct request_queue *, struct request *);
 extern struct request *blk_get_request(struct request_queue *, int, gfp_t);
+extern struct request *blk_make_request(struct request_queue *, struct bio *,
+                                       gfp_t);
 extern void blk_insert_request(struct request_queue *, struct request *, int, void *);
 extern void blk_requeue_request(struct request_queue *, struct request *);
 extern int blk_rq_check_limits(struct request_queue *q, struct request *rq);
 extern int blk_lld_busy(struct request_queue *q);
+extern int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
+                            struct bio_set *bs, gfp_t gfp_mask,
+                            int (*bio_ctr)(struct bio *, struct bio *, void *),
+                            void *data);
+extern void blk_rq_unprep_clone(struct request *rq);
 extern int blk_insert_cloned_request(struct request_queue *q,
                                     struct request *rq);
 extern void blk_plug_device(struct request_queue *);
@@ -767,12 +781,6 @@ extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t,
 extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t,
                         struct scsi_ioctl_command __user *);
 
-/*
- * Temporary export, until SCSI gets fixed up.
- */
-extern int blk_rq_append_bio(struct request_queue *q, struct request *rq,
-                            struct bio *bio);
-
 /*
  * A queue has just exitted congestion.  Note this in the global counter of
  * congested queues, and wake up anyone who was waiting for requests to be
@@ -798,7 +806,6 @@ extern void blk_sync_queue(struct request_queue *q);
 extern void __blk_stop_queue(struct request_queue *q);
 extern void __blk_run_queue(struct request_queue *);
 extern void blk_run_queue(struct request_queue *);
-extern void blk_start_queueing(struct request_queue *);
 extern int blk_rq_map_user(struct request_queue *, struct request *,
                           struct rq_map_data *, void __user *, unsigned long,
                           gfp_t);
@@ -831,41 +838,73 @@ static inline void blk_run_address_space(struct address_space *mapping)
                blk_run_backing_dev(mapping->backing_dev_info, NULL);
 }
 
-extern void blkdev_dequeue_request(struct request *req);
+/*
+ * blk_rq_pos()                : the current sector
+ * blk_rq_bytes()      : bytes left in the entire request
+ * blk_rq_cur_bytes()  : bytes left in the current segment
+ * blk_rq_sectors()    : sectors left in the entire request
+ * blk_rq_cur_sectors()        : sectors left in the current segment
+ */
+static inline sector_t blk_rq_pos(const struct request *rq)
+{
+       return rq->__sector;
+}
+
+static inline unsigned int blk_rq_bytes(const struct request *rq)
+{
+       return rq->__data_len;
+}
+
+static inline int blk_rq_cur_bytes(const struct request *rq)
+{
+       return rq->bio ? bio_cur_bytes(rq->bio) : 0;
+}
+
+static inline unsigned int blk_rq_sectors(const struct request *rq)
+{
+       return blk_rq_bytes(rq) >> 9;
+}
+
+static inline unsigned int blk_rq_cur_sectors(const struct request *rq)
+{
+       return blk_rq_cur_bytes(rq) >> 9;
+}
+
+/*
+ * Request issue related functions.
+ */
+extern struct request *blk_peek_request(struct request_queue *q);
+extern void blk_start_request(struct request *rq);
+extern struct request *blk_fetch_request(struct request_queue *q);
 
 /*
- * blk_end_request() and friends.
- * __blk_end_request() and end_request() must be called with
- * the request queue spinlock acquired.
+ * Request completion related functions.
+ *
+ * blk_update_request() completes given number of bytes and updates
+ * the request without completing it.
+ *
+ * blk_end_request() and friends.  __blk_end_request() must be called
+ * with the request queue spinlock acquired.
  *
  * Several drivers define their own end_request and call
  * blk_end_request() for parts of the original function.
  * This prevents code duplication in drivers.
  */
-extern int blk_end_request(struct request *rq, int error,
-                               unsigned int nr_bytes);
-extern int __blk_end_request(struct request *rq, int error,
-                               unsigned int nr_bytes);
-extern int blk_end_bidi_request(struct request *rq, int error,
-                               unsigned int nr_bytes, unsigned int bidi_bytes);
-extern void end_request(struct request *, int);
-extern int blk_end_request_callback(struct request *rq, int error,
-                               unsigned int nr_bytes,
-                               int (drv_callback)(struct request *));
+extern bool blk_update_request(struct request *rq, int error,
+                              unsigned int nr_bytes);
+extern bool blk_end_request(struct request *rq, int error,
+                           unsigned int nr_bytes);
+extern void blk_end_request_all(struct request *rq, int error);
+extern bool blk_end_request_cur(struct request *rq, int error);
+extern bool __blk_end_request(struct request *rq, int error,
+                             unsigned int nr_bytes);
+extern void __blk_end_request_all(struct request *rq, int error);
+extern bool __blk_end_request_cur(struct request *rq, int error);
+
 extern void blk_complete_request(struct request *);
 extern void __blk_complete_request(struct request *);
 extern void blk_abort_request(struct request *);
 extern void blk_abort_queue(struct request_queue *);
-extern void blk_update_request(struct request *rq, int error,
-                              unsigned int nr_bytes);
-
-/*
- * blk_end_request() takes bytes instead of sectors as a complete size.
- * blk_rq_bytes() returns bytes left to complete in the entire request.
- * blk_rq_cur_bytes() returns bytes left to complete in the current segment.
- */
-extern unsigned int blk_rq_bytes(struct request *rq);
-extern unsigned int blk_rq_cur_bytes(struct request *rq);
 
 /*
  * Access functions for manipulating queue properties
@@ -877,10 +916,20 @@ extern void blk_cleanup_queue(struct request_queue *);
 extern void blk_queue_make_request(struct request_queue *, make_request_fn *);
 extern void blk_queue_bounce_limit(struct request_queue *, u64);
 extern void blk_queue_max_sectors(struct request_queue *, unsigned int);
+extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int);
 extern void blk_queue_max_phys_segments(struct request_queue *, unsigned short);
 extern void blk_queue_max_hw_segments(struct request_queue *, unsigned short);
 extern void blk_queue_max_segment_size(struct request_queue *, unsigned int);
-extern void blk_queue_hardsect_size(struct request_queue *, unsigned short);
+extern void blk_queue_logical_block_size(struct request_queue *, unsigned short);
+extern void blk_queue_physical_block_size(struct request_queue *, unsigned short);
+extern void blk_queue_alignment_offset(struct request_queue *q,
+                                      unsigned int alignment);
+extern void blk_queue_io_min(struct request_queue *q, unsigned int min);
+extern void blk_queue_io_opt(struct request_queue *q, unsigned int opt);
+extern int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
+                           sector_t offset);
+extern void disk_stack_limits(struct gendisk *disk, struct block_device *bdev,
+                             sector_t offset);
 extern void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b);
 extern void blk_queue_dma_pad(struct request_queue *, unsigned int);
 extern void blk_queue_update_dma_pad(struct request_queue *, unsigned int);
@@ -967,19 +1016,87 @@ extern void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter);
 
 #define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist)
 
-static inline int queue_hardsect_size(struct request_queue *q)
+static inline unsigned long queue_bounce_pfn(struct request_queue *q)
+{
+       return q->limits.bounce_pfn;
+}
+
+static inline unsigned long queue_segment_boundary(struct request_queue *q)
+{
+       return q->limits.seg_boundary_mask;
+}
+
+static inline unsigned int queue_max_sectors(struct request_queue *q)
+{
+       return q->limits.max_sectors;
+}
+
+static inline unsigned int queue_max_hw_sectors(struct request_queue *q)
+{
+       return q->limits.max_hw_sectors;
+}
+
+static inline unsigned short queue_max_hw_segments(struct request_queue *q)
+{
+       return q->limits.max_hw_segments;
+}
+
+static inline unsigned short queue_max_phys_segments(struct request_queue *q)
+{
+       return q->limits.max_phys_segments;
+}
+
+static inline unsigned int queue_max_segment_size(struct request_queue *q)
+{
+       return q->limits.max_segment_size;
+}
+
+static inline unsigned short queue_logical_block_size(struct request_queue *q)
 {
        int retval = 512;
 
-       if (q && q->hardsect_size)
-               retval = q->hardsect_size;
+       if (q && q->limits.logical_block_size)
+               retval = q->limits.logical_block_size;
 
        return retval;
 }
 
-static inline int bdev_hardsect_size(struct block_device *bdev)
+static inline unsigned short bdev_logical_block_size(struct block_device *bdev)
+{
+       return queue_logical_block_size(bdev_get_queue(bdev));
+}
+
+static inline unsigned int queue_physical_block_size(struct request_queue *q)
+{
+       return q->limits.physical_block_size;
+}
+
+static inline unsigned int queue_io_min(struct request_queue *q)
+{
+       return q->limits.io_min;
+}
+
+static inline unsigned int queue_io_opt(struct request_queue *q)
+{
+       return q->limits.io_opt;
+}
+
+static inline int queue_alignment_offset(struct request_queue *q)
+{
+       if (q && q->limits.misaligned)
+               return -1;
+
+       if (q && q->limits.alignment_offset)
+               return q->limits.alignment_offset;
+
+       return 0;
+}
+
+static inline int queue_sector_alignment_offset(struct request_queue *q,
+                                               sector_t sector)
 {
-       return queue_hardsect_size(bdev_get_queue(bdev));
+       return ((sector << 9) - q->limits.alignment_offset)
+               & (q->limits.io_min - 1);
 }
 
 static inline int queue_dma_alignment(struct request_queue *q)
index d960889e92efa17a73ee8038603a622be8dcf8a0..7e4350ece0f8dd495398ca4cbf41c95e995b6525 100644 (file)
@@ -116,9 +116,9 @@ struct blk_io_trace {
  * The remap event
  */
 struct blk_io_trace_remap {
-       __be32 device;
        __be32 device_from;
-       __be64 sector;
+       __be32 device_to;
+       __be64 sector_from;
 };
 
 enum {
@@ -165,8 +165,9 @@ struct blk_trace {
 
 extern int blk_trace_ioctl(struct block_device *, unsigned, char __user *);
 extern void blk_trace_shutdown(struct request_queue *);
-extern int do_blk_trace_setup(struct request_queue *q,
-       char *name, dev_t dev, struct blk_user_trace_setup *buts);
+extern int do_blk_trace_setup(struct request_queue *q, char *name,
+                             dev_t dev, struct block_device *bdev,
+                             struct blk_user_trace_setup *buts);
 extern void __trace_note_message(struct blk_trace *, const char *fmt, ...);
 
 /**
@@ -193,22 +194,42 @@ extern void __trace_note_message(struct blk_trace *, const char *fmt, ...);
 extern void blk_add_driver_data(struct request_queue *q, struct request *rq,
                                void *data, size_t len);
 extern int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
+                          struct block_device *bdev,
                           char __user *arg);
 extern int blk_trace_startstop(struct request_queue *q, int start);
 extern int blk_trace_remove(struct request_queue *q);
+extern int blk_trace_init_sysfs(struct device *dev);
 
 extern struct attribute_group blk_trace_attr_group;
 
 #else /* !CONFIG_BLK_DEV_IO_TRACE */
-#define blk_trace_ioctl(bdev, cmd, arg)                (-ENOTTY)
-#define blk_trace_shutdown(q)                  do { } while (0)
-#define do_blk_trace_setup(q, name, dev, buts) (-ENOTTY)
-#define blk_add_driver_data(q, rq, data, len)  do {} while (0)
-#define blk_trace_setup(q, name, dev, arg)     (-ENOTTY)
-#define blk_trace_startstop(q, start)          (-ENOTTY)
-#define blk_trace_remove(q)                    (-ENOTTY)
-#define blk_add_trace_msg(q, fmt, ...)         do { } while (0)
+# define blk_trace_ioctl(bdev, cmd, arg)               (-ENOTTY)
+# define blk_trace_shutdown(q)                         do { } while (0)
+# define do_blk_trace_setup(q, name, dev, bdev, buts)  (-ENOTTY)
+# define blk_add_driver_data(q, rq, data, len)         do {} while (0)
+# define blk_trace_setup(q, name, dev, bdev, arg)      (-ENOTTY)
+# define blk_trace_startstop(q, start)                 (-ENOTTY)
+# define blk_trace_remove(q)                           (-ENOTTY)
+# define blk_add_trace_msg(q, fmt, ...)                        do { } while (0)
+static inline int blk_trace_init_sysfs(struct device *dev)
+{
+       return 0;
+}
 
 #endif /* CONFIG_BLK_DEV_IO_TRACE */
+
+#if defined(CONFIG_EVENT_TRACING) && defined(CONFIG_BLOCK)
+
+static inline int blk_cmd_buf_len(struct request *rq)
+{
+       return blk_pc_request(rq) ? rq->cmd_len * 3 : 1;
+}
+
+extern void blk_dump_cmd(char *buf, struct request *rq);
+extern void blk_fill_rwbs(char *rwbs, u32 rw, int bytes);
+extern void blk_fill_rwbs_rq(char *rwbs, struct request *rq);
+
+#endif /* CONFIG_EVENT_TRACING && CONFIG_BLOCK */
+
 #endif /* __KERNEL__ */
 #endif
index 5a40d14daa9fab04bf641c1a11d82a1610ff7753..c56457c8334eea7ece9236c963fec845791909ba 100644 (file)
@@ -288,7 +288,15 @@ static inline cycle_t clocksource_read(struct clocksource *cs)
  */
 static inline int clocksource_enable(struct clocksource *cs)
 {
-       return cs->enable ? cs->enable(cs) : 0;
+       int ret = 0;
+
+       if (cs->enable)
+               ret = cs->enable(cs);
+
+       /* save mult_orig on enable */
+       cs->mult_orig = cs->mult;
+
+       return ret;
 }
 
 /**
index f2ded21f9a3c37cdef070315659c57d5a066f4f9..af931ee43dd8e43454b9cd9d389ec0bd5b1a7b21 100644 (file)
@@ -222,6 +222,8 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from);
 int copy_siginfo_to_user32(struct compat_siginfo __user *to, siginfo_t *from);
 int get_compat_sigevent(struct sigevent *event,
                const struct compat_sigevent __user *u_event);
+long compat_sys_rt_tgsigqueueinfo(compat_pid_t tgid, compat_pid_t pid, int sig,
+                                 struct compat_siginfo __user *uinfo);
 
 static inline int compat_timeval_compare(struct compat_timeval *lhs,
                                        struct compat_timeval *rhs)
index 788850ba4e7577def670ea0fba81b14ba0a932a0..1fbdea4f08ebbb059d060cb01e431b7d65f23efc 100644 (file)
@@ -142,19 +142,6 @@ struct CYZ_BOOT_CTRL {
 
 
 #ifndef DP_WINDOW_SIZE
-/* #include "cyclomz.h" */
-/****************** ****************** *******************/
-/*
- *     The data types defined below are used in all ZFIRM interface
- *     data structures. They accomodate differences between HW
- *     architectures and compilers.
- */
-
-typedef __u64  ucdouble;               /* 64 bits, unsigned */
-typedef __u32  uclong;                 /* 32 bits, unsigned */
-typedef __u16  ucshort;                /* 16 bits, unsigned */
-typedef __u8   ucchar;                 /* 8 bits, unsigned */
-
 /*
  *     Memory Window Sizes
  */
@@ -507,16 +494,20 @@ struct ZFW_CTRL {
 
 /* Per card data structure */
 struct cyclades_card {
-    void __iomem *base_addr;
-    void __iomem *ctl_addr;
-    int irq;
-    unsigned int num_chips;    /* 0 if card absent, -1 if Z/PCI, else Y */
-    unsigned int first_line;   /* minor number of first channel on card */
-    unsigned int nports;       /* Number of ports in the card */
-    int bus_index;             /* address shift - 0 for ISA, 1 for PCI */
-    int intr_enabled;          /* FW Interrupt flag - 0 disabled, 1 enabled */
-    spinlock_t card_lock;
-    struct cyclades_port *ports;
+       void __iomem *base_addr;
+       union {
+               void __iomem *p9050;
+               struct RUNTIME_9060 __iomem *p9060;
+       } ctl_addr;
+       int irq;
+       unsigned int num_chips; /* 0 if card absent, -1 if Z/PCI, else Y */
+       unsigned int first_line;        /* minor number of first channel on card */
+       unsigned int nports;    /* Number of ports in the card */
+       int bus_index;          /* address shift - 0 for ISA, 1 for PCI */
+       int intr_enabled;               /* FW Interrupt flag - 0 disabled, 1 enabled */
+       u32 hw_ver;
+       spinlock_t card_lock;
+       struct cyclades_port *ports;
 };
 
 /***************************************
index ded2d7c42668ccc396f193ae3c157cf0ea024133..49c2362977fde10457c72d00e3672ba71142cd42 100644 (file)
@@ -149,7 +149,7 @@ struct io_restrictions {
        unsigned max_hw_sectors;
        unsigned max_sectors;
        unsigned max_segment_size;
-       unsigned short hardsect_size;
+       unsigned short logical_block_size;
        unsigned short max_hw_segments;
        unsigned short max_phys_segments;
        unsigned char no_cluster; /* inverted so that 0 is default */
index 28d53cb7b5a22c099feb9a2aa19b2e3010e8d124..171ad8aedc835258e152b94b2bc92242045d9c3e 100644 (file)
@@ -32,6 +32,8 @@ extern void dma_debug_add_bus(struct bus_type *bus);
 
 extern void dma_debug_init(u32 num_entries);
 
+extern int dma_debug_resize_entries(u32 num_entries);
+
 extern void debug_dma_map_page(struct device *dev, struct page *page,
                               size_t offset, size_t size,
                               int direction, dma_addr_t dma_addr,
@@ -91,6 +93,11 @@ static inline void dma_debug_init(u32 num_entries)
 {
 }
 
+static inline int dma_debug_resize_entries(u32 num_entries)
+{
+       return 0;
+}
+
 static inline void debug_dma_map_page(struct device *dev, struct page *page,
                                      size_t offset, size_t size,
                                      int direction, dma_addr_t dma_addr,
index e397dc342cdaf1eaf99b022b4523f858d9f3e886..10ff5c498824b5b8dc5e963b07563878a13c2667 100644 (file)
@@ -108,6 +108,7 @@ struct irte {
 };
 #ifdef CONFIG_INTR_REMAP
 extern int intr_remapping_enabled;
+extern int intr_remapping_supported(void);
 extern int enable_intr_remapping(int);
 extern void disable_intr_remapping(void);
 extern int reenable_intr_remapping(int);
@@ -157,6 +158,8 @@ static inline struct intel_iommu *map_ioapic_to_ir(int apic)
 }
 #define irq_remapped(irq)              (0)
 #define enable_intr_remapping(mode)    (-1)
+#define disable_intr_remapping()       (0)
+#define reenable_intr_remapping(mode)  (0)
 #define intr_remapping_enabled         (0)
 #endif
 
index c59b769f62b0dcb2582e0a3e9592d19b503d8180..1cb3372e65d89521886a8deb0f08f46c31dfe813 100644 (file)
@@ -103,10 +103,8 @@ extern int elv_merge(struct request_queue *, struct request **, struct bio *);
 extern void elv_merge_requests(struct request_queue *, struct request *,
                               struct request *);
 extern void elv_merged_request(struct request_queue *, struct request *, int);
-extern void elv_dequeue_request(struct request_queue *, struct request *);
 extern void elv_requeue_request(struct request_queue *, struct request *);
 extern int elv_queue_empty(struct request_queue *);
-extern struct request *elv_next_request(struct request_queue *q);
 extern struct request *elv_former_request(struct request_queue *, struct request *);
 extern struct request *elv_latter_request(struct request_queue *, struct request *);
 extern int elv_register_queue(struct request_queue *q);
@@ -171,7 +169,7 @@ enum {
        ELV_MQUEUE_MUST,
 };
 
-#define rq_end_sector(rq)      ((rq)->sector + (rq)->nr_sectors)
+#define rq_end_sector(rq)      (blk_rq_pos(rq) + blk_rq_sectors(rq))
 #define rb_entry_rq(node)      rb_entry((node), struct request, rb_node)
 
 /*
index 3b534e527e09922aa0d89b1854ba60a4e5871f5a..83d6b4397245bdbb44f27d9f7cbdfa763ff96767 100644 (file)
@@ -2205,6 +2205,8 @@ extern int generic_segment_checks(const struct iovec *iov,
 /* fs/splice.c */
 extern ssize_t generic_file_splice_read(struct file *, loff_t *,
                struct pipe_inode_info *, size_t, unsigned int);
+extern ssize_t default_file_splice_read(struct file *, loff_t *,
+               struct pipe_inode_info *, size_t, unsigned int);
 extern ssize_t generic_file_splice_write(struct pipe_inode_info *,
                struct file *, loff_t *, size_t, unsigned int);
 extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
index 8a0c2f221e6b95b448991b1e291610c9e52ea91e..39b95c56587e8f1f8852aed9318148fcc16aac56 100644 (file)
@@ -233,8 +233,6 @@ extern int ftrace_arch_read_dyn_info(char *buf, int size);
 
 extern int skip_trace(unsigned long ip);
 
-extern void ftrace_release(void *start, unsigned long size);
-
 extern void ftrace_disable_daemon(void);
 extern void ftrace_enable_daemon(void);
 #else
@@ -325,13 +323,8 @@ static inline void __ftrace_enabled_restore(int enabled)
 
 #ifdef CONFIG_FTRACE_MCOUNT_RECORD
 extern void ftrace_init(void);
-extern void ftrace_init_module(struct module *mod,
-                              unsigned long *start, unsigned long *end);
 #else
 static inline void ftrace_init(void) { }
-static inline void
-ftrace_init_module(struct module *mod,
-                  unsigned long *start, unsigned long *end) { }
 #endif
 
 /*
@@ -368,6 +361,7 @@ struct ftrace_ret_stack {
        unsigned long ret;
        unsigned long func;
        unsigned long long calltime;
+       unsigned long long subtime;
 };
 
 /*
@@ -379,8 +373,6 @@ extern void return_to_handler(void);
 
 extern int
 ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth);
-extern void
-ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret);
 
 /*
  * Sometimes we don't want to trace a function with the function
@@ -496,8 +488,15 @@ static inline int test_tsk_trace_graph(struct task_struct *tsk)
 
 extern int ftrace_dump_on_oops;
 
+#ifdef CONFIG_PREEMPT
+#define INIT_TRACE_RECURSION           .trace_recursion = 0,
+#endif
+
 #endif /* CONFIG_TRACING */
 
+#ifndef INIT_TRACE_RECURSION
+#define INIT_TRACE_RECURSION
+#endif
 
 #ifdef CONFIG_HW_BRANCH_TRACER
 
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
new file mode 100644 (file)
index 0000000..5c093ff
--- /dev/null
@@ -0,0 +1,172 @@
+#ifndef _LINUX_FTRACE_EVENT_H
+#define _LINUX_FTRACE_EVENT_H
+
+#include <linux/trace_seq.h>
+#include <linux/ring_buffer.h>
+#include <linux/percpu.h>
+
+struct trace_array;
+struct tracer;
+struct dentry;
+
+DECLARE_PER_CPU(struct trace_seq, ftrace_event_seq);
+
+struct trace_print_flags {
+       unsigned long           mask;
+       const char              *name;
+};
+
+const char *ftrace_print_flags_seq(struct trace_seq *p, const char *delim,
+                                  unsigned long flags,
+                                  const struct trace_print_flags *flag_array);
+
+const char *ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,
+                                    const struct trace_print_flags *symbol_array);
+
+/*
+ * The trace entry - the most basic unit of tracing. This is what
+ * is printed in the end as a single line in the trace output, such as:
+ *
+ *     bash-15816 [01]   235.197585: idle_cpu <- irq_enter
+ */
+struct trace_entry {
+       unsigned short          type;
+       unsigned char           flags;
+       unsigned char           preempt_count;
+       int                     pid;
+       int                     tgid;
+};
+
+#define FTRACE_MAX_EVENT                                               \
+       ((1 << (sizeof(((struct trace_entry *)0)->type) * 8)) - 1)
+
+/*
+ * Trace iterator - used by printout routines who present trace
+ * results to users and which routines might sleep, etc:
+ */
+struct trace_iterator {
+       struct trace_array      *tr;
+       struct tracer           *trace;
+       void                    *private;
+       int                     cpu_file;
+       struct mutex            mutex;
+       struct ring_buffer_iter *buffer_iter[NR_CPUS];
+       unsigned long           iter_flags;
+
+       /* The below is zeroed out in pipe_read */
+       struct trace_seq        seq;
+       struct trace_entry      *ent;
+       int                     cpu;
+       u64                     ts;
+
+       loff_t                  pos;
+       long                    idx;
+
+       cpumask_var_t           started;
+};
+
+
+typedef enum print_line_t (*trace_print_func)(struct trace_iterator *iter,
+                                             int flags);
+struct trace_event {
+       struct hlist_node       node;
+       struct list_head        list;
+       int                     type;
+       trace_print_func        trace;
+       trace_print_func        raw;
+       trace_print_func        hex;
+       trace_print_func        binary;
+};
+
+extern int register_ftrace_event(struct trace_event *event);
+extern int unregister_ftrace_event(struct trace_event *event);
+
+/* Return values for print_line callback */
+enum print_line_t {
+       TRACE_TYPE_PARTIAL_LINE = 0,    /* Retry after flushing the seq */
+       TRACE_TYPE_HANDLED      = 1,
+       TRACE_TYPE_UNHANDLED    = 2,    /* Relay to other output functions */
+       TRACE_TYPE_NO_CONSUME   = 3     /* Handled but ask to not consume */
+};
+
+
+struct ring_buffer_event *
+trace_current_buffer_lock_reserve(int type, unsigned long len,
+                                 unsigned long flags, int pc);
+void trace_current_buffer_unlock_commit(struct ring_buffer_event *event,
+                                       unsigned long flags, int pc);
+void trace_nowake_buffer_unlock_commit(struct ring_buffer_event *event,
+                                       unsigned long flags, int pc);
+void trace_current_buffer_discard_commit(struct ring_buffer_event *event);
+
+void tracing_record_cmdline(struct task_struct *tsk);
+
+struct ftrace_event_call {
+       struct list_head        list;
+       char                    *name;
+       char                    *system;
+       struct dentry           *dir;
+       struct trace_event      *event;
+       int                     enabled;
+       int                     (*regfunc)(void);
+       void                    (*unregfunc)(void);
+       int                     id;
+       int                     (*raw_init)(void);
+       int                     (*show_format)(struct trace_seq *s);
+       int                     (*define_fields)(void);
+       struct list_head        fields;
+       int                     filter_active;
+       void                    *filter;
+       void                    *mod;
+
+#ifdef CONFIG_EVENT_PROFILE
+       atomic_t        profile_count;
+       int             (*profile_enable)(struct ftrace_event_call *);
+       void            (*profile_disable)(struct ftrace_event_call *);
+#endif
+};
+
+#define MAX_FILTER_PRED                32
+#define MAX_FILTER_STR_VAL     128
+
+extern int init_preds(struct ftrace_event_call *call);
+extern void destroy_preds(struct ftrace_event_call *call);
+extern int filter_match_preds(struct ftrace_event_call *call, void *rec);
+extern int filter_current_check_discard(struct ftrace_event_call *call,
+                                       void *rec,
+                                       struct ring_buffer_event *event);
+
+extern int trace_define_field(struct ftrace_event_call *call, char *type,
+                             char *name, int offset, int size, int is_signed);
+
+#define is_signed_type(type)   (((type)(-1)) < 0)
+
+int trace_set_clr_event(const char *system, const char *event, int set);
+
+/*
+ * The double __builtin_constant_p is because gcc will give us an error
+ * if we try to allocate the static variable to fmt if it is not a
+ * constant. Even with the outer if statement optimizing out.
+ */
+#define event_trace_printk(ip, fmt, args...)                           \
+do {                                                                   \
+       __trace_printk_check_format(fmt, ##args);                       \
+       tracing_record_cmdline(current);                                \
+       if (__builtin_constant_p(fmt)) {                                \
+               static const char *trace_printk_fmt                     \
+                 __attribute__((section("__trace_printk_fmt"))) =      \
+                       __builtin_constant_p(fmt) ? fmt : NULL;         \
+                                                                       \
+               __trace_bprintk(ip, trace_printk_fmt, ##args);          \
+       } else                                                          \
+               __trace_printk(ip, fmt, ##args);                        \
+} while (0)
+
+#define __common_field(type, item, is_signed)                          \
+       ret = trace_define_field(event_call, #type, "common_" #item,    \
+                                offsetof(typeof(field.ent), item),     \
+                                sizeof(field.ent.item), is_signed);    \
+       if (ret)                                                        \
+               return ret;
+
+#endif /* _LINUX_FTRACE_EVENT_H */
index 3bf5bb5a34f9fba43b9248caf434eb6059e6329e..34956c8fdebf8df63ab44c1f84b136406b3d0f34 100644 (file)
@@ -23,6 +23,8 @@ union ktime;
 #define FUTEX_TRYLOCK_PI       8
 #define FUTEX_WAIT_BITSET      9
 #define FUTEX_WAKE_BITSET      10
+#define FUTEX_WAIT_REQUEUE_PI  11
+#define FUTEX_CMP_REQUEUE_PI   12
 
 #define FUTEX_PRIVATE_FLAG     128
 #define FUTEX_CLOCK_REALTIME   256
@@ -38,6 +40,10 @@ union ktime;
 #define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
 #define FUTEX_WAIT_BITSET_PRIVATE      (FUTEX_WAIT_BITS | FUTEX_PRIVATE_FLAG)
 #define FUTEX_WAKE_BITSET_PRIVATE      (FUTEX_WAKE_BITS | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAIT_REQUEUE_PI_PRIVATE  (FUTEX_WAIT_REQUEUE_PI | \
+                                        FUTEX_PRIVATE_FLAG)
+#define FUTEX_CMP_REQUEUE_PI_PRIVATE   (FUTEX_CMP_REQUEUE_PI | \
+                                        FUTEX_PRIVATE_FLAG)
 
 /*
  * Support for robust futexes: the kernel cleans up held futexes at
index a1a28caed23dc1bca05a2c661b91ad4e3a094568..149fda264c86c9a404befd350d1a7c2006ab3213 100644 (file)
@@ -90,6 +90,7 @@ struct disk_stats {
 struct hd_struct {
        sector_t start_sect;
        sector_t nr_sects;
+       sector_t alignment_offset;
        struct device __dev;
        struct kobject *holder_dir;
        int policy, partno;
index 9fed365a598b89845d83271f93d9fe3affef15f2..867cb68d84619a8631670f839bf908a2db99b56b 100644 (file)
@@ -26,6 +26,9 @@
 #include <asm/io.h>
 #include <asm/mutex.h>
 
+/* for request_sense */
+#include <linux/cdrom.h>
+
 #if defined(CONFIG_CRIS) || defined(CONFIG_FRV) || defined(CONFIG_MN10300)
 # define SUPPORT_VLB_SYNC 0
 #else
@@ -324,7 +327,6 @@ struct ide_cmd {
        unsigned int            cursg_ofs;
 
        struct request          *rq;            /* copy of request */
-       void                    *special;       /* valid_t generally */
 };
 
 /* ATAPI packet command flags */
@@ -360,11 +362,7 @@ struct ide_atapi_pc {
 
        /* data buffer */
        u8 *buf;
-       /* current buffer position */
-       u8 *cur_pos;
        int buf_size;
-       /* missing/available data on the current buffer */
-       int b_count;
 
        /* the corresponding request */
        struct request *rq;
@@ -377,10 +375,6 @@ struct ide_atapi_pc {
         */
        u8 pc_buf[IDE_PC_BUFFER_SIZE];
 
-       /* idetape only */
-       struct idetape_bh *bh;
-       char *b_data;
-
        unsigned long timeout;
 };
 
@@ -593,16 +587,16 @@ struct ide_drive_s {
        /* callback for packet commands */
        int  (*pc_callback)(struct ide_drive_s *, int);
 
-       void (*pc_update_buffers)(struct ide_drive_s *, struct ide_atapi_pc *);
-       int  (*pc_io_buffers)(struct ide_drive_s *, struct ide_atapi_pc *,
-                             unsigned int, int);
-
        ide_startstop_t (*irq_handler)(struct ide_drive_s *);
 
        unsigned long atapi_flags;
 
        struct ide_atapi_pc request_sense_pc;
-       struct request request_sense_rq;
+
+       /* current sense rq and buffer */
+       bool sense_rq_armed;
+       struct request sense_rq;
+       struct request_sense sense_data;
 };
 
 typedef struct ide_drive_s ide_drive_t;
@@ -1174,7 +1168,10 @@ int ide_do_test_unit_ready(ide_drive_t *, struct gendisk *);
 int ide_do_start_stop(ide_drive_t *, struct gendisk *, int);
 int ide_set_media_lock(ide_drive_t *, struct gendisk *, int);
 void ide_create_request_sense_cmd(ide_drive_t *, struct ide_atapi_pc *);
-void ide_retry_pc(ide_drive_t *, struct gendisk *);
+void ide_retry_pc(ide_drive_t *drive);
+
+void ide_prep_sense(ide_drive_t *drive, struct request *rq);
+int ide_queue_sense_rq(ide_drive_t *drive, void *special);
 
 int ide_cd_expiry(ide_drive_t *);
 
index 0e2aa45cb0cefdfa3fc3727fe0a62926f1755172..b1b827d091a995e3d5b2e4a0d1e7f18e975e9319 100644 (file)
 #include <linux/fs.h>
 struct linux_binprm;
 
+#define IMA_COUNT_UPDATE 1
+#define IMA_COUNT_LEAVE 0
+
 #ifdef CONFIG_IMA
 extern int ima_bprm_check(struct linux_binprm *bprm);
 extern int ima_inode_alloc(struct inode *inode);
 extern void ima_inode_free(struct inode *inode);
-extern int ima_path_check(struct path *path, int mask);
+extern int ima_path_check(struct path *path, int mask, int update_counts);
 extern void ima_file_free(struct file *file);
 extern int ima_file_mmap(struct file *file, unsigned long prot);
-extern void ima_shm_check(struct file *file);
+extern void ima_counts_get(struct file *file);
 
 #else
 static inline int ima_bprm_check(struct linux_binprm *bprm)
@@ -38,7 +41,7 @@ static inline void ima_inode_free(struct inode *inode)
        return;
 }
 
-static inline int ima_path_check(struct path *path, int mask)
+static inline int ima_path_check(struct path *path, int mask, int update_counts)
 {
        return 0;
 }
@@ -53,7 +56,7 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot)
        return 0;
 }
 
-static inline void ima_shm_check(struct file *file)
+static inline void ima_counts_get(struct file *file)
 {
        return;
 }
index d87247d2641f5cbf4eb69a90fea392b95684e588..6646bfc7b8929aeadbc1c12dbdd6f48dc07d7722 100644 (file)
@@ -145,8 +145,8 @@ extern struct cred init_cred;
        .group_leader   = &tsk,                                         \
        .real_cred      = &init_cred,                                   \
        .cred           = &init_cred,                                   \
-       .cred_exec_mutex =                                              \
-                __MUTEX_INITIALIZER(tsk.cred_exec_mutex),              \
+       .cred_guard_mutex =                                             \
+                __MUTEX_INITIALIZER(tsk.cred_guard_mutex),             \
        .comm           = "swapper",                                    \
        .thread         = INIT_THREAD,                                  \
        .fs             = &init_fs,                                     \
@@ -174,6 +174,7 @@ extern struct cred init_cred;
        INIT_TRACE_IRQFLAGS                                             \
        INIT_LOCKDEP                                                    \
        INIT_FTRACE_GRAPH                                               \
+       INIT_TRACE_RECURSION                                            \
 }
 
 
index 91bb76f44f14e6488e909669ba3e3e94fba1104a..ff374ceface08d55c889c5698cdf6bcfda753655 100644 (file)
@@ -566,6 +566,6 @@ struct irq_desc;
 extern int early_irq_init(void);
 extern int arch_probe_nr_irqs(void);
 extern int arch_early_irq_init(void);
-extern int arch_init_chip_data(struct irq_desc *desc, int cpu);
+extern int arch_init_chip_data(struct irq_desc *desc, int node);
 
 #endif
index 08b987bccf89aff533268c0718770583ba204026..dd05434fa45f206f1e7c18995bcbe49fbb741a85 100644 (file)
@@ -64,7 +64,7 @@ struct cfq_io_context {
  * and kmalloc'ed. These could be shared between processes.
  */
 struct io_context {
-       atomic_t refcount;
+       atomic_long_t refcount;
        atomic_t nr_tasks;
 
        /* all the fields below are protected by this lock */
@@ -91,8 +91,8 @@ static inline struct io_context *ioc_task_link(struct io_context *ioc)
         * if ref count is zero, don't allow sharing (ioc is going away, it's
         * a race).
         */
-       if (ioc && atomic_inc_not_zero(&ioc->refcount)) {
-               atomic_inc(&ioc->nr_tasks);
+       if (ioc && atomic_long_inc_not_zero(&ioc->refcount)) {
+               atomic_long_inc(&ioc->refcount);
                return ioc;
        }
 
index b7cbeed972e425b694f1666343f6fc0558ac439e..eedbb8e5e0ccff99c79594b6485fd9259049d088 100644 (file)
@@ -117,7 +117,7 @@ struct irq_chip {
        void            (*eoi)(unsigned int irq);
 
        void            (*end)(unsigned int irq);
-       void            (*set_affinity)(unsigned int irq,
+       int             (*set_affinity)(unsigned int irq,
                                        const struct cpumask *dest);
        int             (*retrigger)(unsigned int irq);
        int             (*set_type)(unsigned int irq, unsigned int flow_type);
@@ -187,7 +187,7 @@ struct irq_desc {
        spinlock_t              lock;
 #ifdef CONFIG_SMP
        cpumask_var_t           affinity;
-       unsigned int            cpu;
+       unsigned int            node;
 #ifdef CONFIG_GENERIC_PENDING_IRQ
        cpumask_var_t           pending_mask;
 #endif
@@ -201,26 +201,23 @@ struct irq_desc {
 } ____cacheline_internodealigned_in_smp;
 
 extern void arch_init_copy_chip_data(struct irq_desc *old_desc,
-                                       struct irq_desc *desc, int cpu);
+                                       struct irq_desc *desc, int node);
 extern void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc);
 
 #ifndef CONFIG_SPARSE_IRQ
 extern struct irq_desc irq_desc[NR_IRQS];
-#else /* CONFIG_SPARSE_IRQ */
-extern struct irq_desc *move_irq_desc(struct irq_desc *old_desc, int cpu);
-#endif /* CONFIG_SPARSE_IRQ */
-
-extern struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu);
+#endif
 
-static inline struct irq_desc *
-irq_remap_to_desc(unsigned int irq, struct irq_desc *desc)
-{
-#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
-       return irq_to_desc(irq);
+#ifdef CONFIG_NUMA_IRQ_DESC
+extern struct irq_desc *move_irq_desc(struct irq_desc *old_desc, int node);
 #else
+static inline struct irq_desc *move_irq_desc(struct irq_desc *desc, int node)
+{
        return desc;
-#endif
 }
+#endif
+
+extern struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node);
 
 /*
  * Migration helpers for obsolete names, they will go away:
@@ -386,7 +383,7 @@ extern void set_irq_noprobe(unsigned int irq);
 extern void set_irq_probe(unsigned int irq);
 
 /* Handle dynamic irq creation and destruction */
-extern unsigned int create_irq_nr(unsigned int irq_want);
+extern unsigned int create_irq_nr(unsigned int irq_want, int node);
 extern int create_irq(void);
 extern void destroy_irq(unsigned int irq);
 
@@ -424,47 +421,48 @@ extern int set_irq_msi(unsigned int irq, struct msi_desc *entry);
 
 #ifdef CONFIG_SMP
 /**
- * init_alloc_desc_masks - allocate cpumasks for irq_desc
+ * alloc_desc_masks - allocate cpumasks for irq_desc
  * @desc:      pointer to irq_desc struct
  * @cpu:       cpu which will be handling the cpumasks
  * @boot:      true if need bootmem
  *
  * Allocates affinity and pending_mask cpumask if required.
  * Returns true if successful (or not required).
- * Side effect: affinity has all bits set, pending_mask has all bits clear.
  */
-static inline bool init_alloc_desc_masks(struct irq_desc *desc, int cpu,
+static inline bool alloc_desc_masks(struct irq_desc *desc, int node,
                                                                bool boot)
 {
-       int node;
-
+#ifdef CONFIG_CPUMASK_OFFSTACK
        if (boot) {
                alloc_bootmem_cpumask_var(&desc->affinity);
-               cpumask_setall(desc->affinity);
 
 #ifdef CONFIG_GENERIC_PENDING_IRQ
                alloc_bootmem_cpumask_var(&desc->pending_mask);
-               cpumask_clear(desc->pending_mask);
 #endif
                return true;
        }
 
-       node = cpu_to_node(cpu);
-
        if (!alloc_cpumask_var_node(&desc->affinity, GFP_ATOMIC, node))
                return false;
-       cpumask_setall(desc->affinity);
 
 #ifdef CONFIG_GENERIC_PENDING_IRQ
        if (!alloc_cpumask_var_node(&desc->pending_mask, GFP_ATOMIC, node)) {
                free_cpumask_var(desc->affinity);
                return false;
        }
-       cpumask_clear(desc->pending_mask);
+#endif
 #endif
        return true;
 }
 
+static inline void init_desc_masks(struct irq_desc *desc)
+{
+       cpumask_setall(desc->affinity);
+#ifdef CONFIG_GENERIC_PENDING_IRQ
+       cpumask_clear(desc->pending_mask);
+#endif
+}
+
 /**
  * init_copy_desc_masks - copy cpumasks for irq_desc
  * @old_desc:  pointer to old irq_desc struct
@@ -478,7 +476,7 @@ static inline bool init_alloc_desc_masks(struct irq_desc *desc, int cpu,
 static inline void init_copy_desc_masks(struct irq_desc *old_desc,
                                        struct irq_desc *new_desc)
 {
-#ifdef CONFIG_CPUMASKS_OFFSTACK
+#ifdef CONFIG_CPUMASK_OFFSTACK
        cpumask_copy(new_desc->affinity, old_desc->affinity);
 
 #ifdef CONFIG_GENERIC_PENDING_IRQ
@@ -499,12 +497,16 @@ static inline void free_desc_masks(struct irq_desc *old_desc,
 
 #else /* !CONFIG_SMP */
 
-static inline bool init_alloc_desc_masks(struct irq_desc *desc, int cpu,
+static inline bool alloc_desc_masks(struct irq_desc *desc, int node,
                                                                bool boot)
 {
        return true;
 }
 
+static inline void init_desc_masks(struct irq_desc *desc)
+{
+}
+
 static inline void init_copy_desc_masks(struct irq_desc *old_desc,
                                        struct irq_desc *new_desc)
 {
diff --git a/include/linux/kmemtrace.h b/include/linux/kmemtrace.h
new file mode 100644 (file)
index 0000000..b616d39
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2008 Eduard - Gabriel Munteanu
+ *
+ * This file is released under GPL version 2.
+ */
+
+#ifndef _LINUX_KMEMTRACE_H
+#define _LINUX_KMEMTRACE_H
+
+#ifdef __KERNEL__
+
+#include <trace/events/kmem.h>
+
+#ifdef CONFIG_KMEMTRACE
+extern void kmemtrace_init(void);
+#else
+static inline void kmemtrace_init(void)
+{
+}
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_KMEMTRACE_H */
+
index 8cc137911b34019ed963bb40260d9a20a0057b1a..3db5d8d3748527a80db4034652f49ed85ee9792d 100644 (file)
@@ -119,7 +119,7 @@ struct kvm_run {
                        __u32 error_code;
                } ex;
                /* KVM_EXIT_IO */
-               struct kvm_io {
+               struct {
 #define KVM_EXIT_IO_IN  0
 #define KVM_EXIT_IO_OUT 1
                        __u8 direction;
@@ -224,10 +224,10 @@ struct kvm_interrupt {
 /* for KVM_GET_DIRTY_LOG */
 struct kvm_dirty_log {
        __u32 slot;
-       __u32 padding;
+       __u32 padding1;
        union {
                void __user *dirty_bitmap; /* one bit per page */
-               __u64 padding;
+               __u64 padding2;
        };
 };
 
@@ -409,6 +409,10 @@ struct kvm_trace_rec {
 #ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
 #define KVM_CAP_DEVICE_DEASSIGNMENT 27
 #endif
+#ifdef __KVM_HAVE_MSIX
+#define KVM_CAP_DEVICE_MSIX 28
+#endif
+#define KVM_CAP_ASSIGN_DEV_IRQ 29
 /* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
 #define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
 
@@ -482,11 +486,18 @@ struct kvm_irq_routing {
 #define KVM_ASSIGN_PCI_DEVICE _IOR(KVMIO, 0x69, \
                                   struct kvm_assigned_pci_dev)
 #define KVM_SET_GSI_ROUTING       _IOW(KVMIO, 0x6a, struct kvm_irq_routing)
+/* deprecated, replaced by KVM_ASSIGN_DEV_IRQ */
 #define KVM_ASSIGN_IRQ _IOR(KVMIO, 0x70, \
                            struct kvm_assigned_irq)
+#define KVM_ASSIGN_DEV_IRQ        _IOW(KVMIO, 0x70, struct kvm_assigned_irq)
 #define KVM_REINJECT_CONTROL      _IO(KVMIO, 0x71)
 #define KVM_DEASSIGN_PCI_DEVICE _IOW(KVMIO, 0x72, \
                                     struct kvm_assigned_pci_dev)
+#define KVM_ASSIGN_SET_MSIX_NR \
+                       _IOW(KVMIO, 0x73, struct kvm_assigned_msix_nr)
+#define KVM_ASSIGN_SET_MSIX_ENTRY \
+                       _IOW(KVMIO, 0x74, struct kvm_assigned_msix_entry)
+#define KVM_DEASSIGN_DEV_IRQ       _IOW(KVMIO, 0x75, struct kvm_assigned_irq)
 
 /*
  * ioctls for vcpu fds
@@ -577,6 +588,8 @@ struct kvm_debug_guest {
 #define KVM_TRC_STLB_INVAL       (KVM_TRC_HANDLER + 0x18)
 #define KVM_TRC_PPC_INSTR        (KVM_TRC_HANDLER + 0x19)
 
+#define KVM_DEV_ASSIGN_ENABLE_IOMMU    (1 << 0)
+
 struct kvm_assigned_pci_dev {
        __u32 assigned_dev_id;
        __u32 busnr;
@@ -587,6 +600,17 @@ struct kvm_assigned_pci_dev {
        };
 };
 
+#define KVM_DEV_IRQ_HOST_INTX    (1 << 0)
+#define KVM_DEV_IRQ_HOST_MSI     (1 << 1)
+#define KVM_DEV_IRQ_HOST_MSIX    (1 << 2)
+
+#define KVM_DEV_IRQ_GUEST_INTX   (1 << 8)
+#define KVM_DEV_IRQ_GUEST_MSI    (1 << 9)
+#define KVM_DEV_IRQ_GUEST_MSIX   (1 << 10)
+
+#define KVM_DEV_IRQ_HOST_MASK   0x00ff
+#define KVM_DEV_IRQ_GUEST_MASK   0xff00
+
 struct kvm_assigned_irq {
        __u32 assigned_dev_id;
        __u32 host_irq;
@@ -602,9 +626,19 @@ struct kvm_assigned_irq {
        };
 };
 
-#define KVM_DEV_ASSIGN_ENABLE_IOMMU    (1 << 0)
 
-#define KVM_DEV_IRQ_ASSIGN_MSI_ACTION  KVM_DEV_IRQ_ASSIGN_ENABLE_MSI
-#define KVM_DEV_IRQ_ASSIGN_ENABLE_MSI  (1 << 0)
+struct kvm_assigned_msix_nr {
+       __u32 assigned_dev_id;
+       __u16 entry_nr;
+       __u16 padding;
+};
+
+#define KVM_MAX_MSIX_PER_DEV           512
+struct kvm_assigned_msix_entry {
+       __u32 assigned_dev_id;
+       __u32 gsi;
+       __u16 entry; /* The index of entry in the MSI-X table */
+       __u16 padding[3];
+};
 
 #endif
index 894a56e365e855e549b12563facda8f24405c15a..aacc5449f586376a6551518c2a946a7a151ada46 100644 (file)
@@ -38,6 +38,7 @@
 #define KVM_REQ_UNHALT             6
 #define KVM_REQ_MMU_SYNC           7
 #define KVM_REQ_KVMCLOCK_UPDATE    8
+#define KVM_REQ_KICK               9
 
 #define KVM_USERSPACE_IRQ_SOURCE_ID    0
 
@@ -72,7 +73,6 @@ struct kvm_vcpu {
        struct mutex mutex;
        int   cpu;
        struct kvm_run *run;
-       int guest_mode;
        unsigned long requests;
        unsigned long guest_debug;
        int fpu_active;
@@ -298,6 +298,7 @@ int kvm_arch_hardware_setup(void);
 void kvm_arch_hardware_unsetup(void);
 void kvm_arch_check_processor_compat(void *rtn);
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu);
+int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu);
 
 void kvm_free_physmem(struct kvm *kvm);
 
@@ -319,6 +320,13 @@ struct kvm_irq_ack_notifier {
        void (*irq_acked)(struct kvm_irq_ack_notifier *kian);
 };
 
+#define KVM_ASSIGNED_MSIX_PENDING              0x1
+struct kvm_guest_msix_entry {
+       u32 vector;
+       u16 entry;
+       u16 flags;
+};
+
 struct kvm_assigned_dev_kernel {
        struct kvm_irq_ack_notifier ack_notifier;
        struct work_struct interrupt_work;
@@ -326,18 +334,18 @@ struct kvm_assigned_dev_kernel {
        int assigned_dev_id;
        int host_busnr;
        int host_devfn;
+       unsigned int entries_nr;
        int host_irq;
        bool host_irq_disabled;
+       struct msix_entry *host_msix_entries;
        int guest_irq;
-#define KVM_ASSIGNED_DEV_GUEST_INTX    (1 << 0)
-#define KVM_ASSIGNED_DEV_GUEST_MSI     (1 << 1)
-#define KVM_ASSIGNED_DEV_HOST_INTX     (1 << 8)
-#define KVM_ASSIGNED_DEV_HOST_MSI      (1 << 9)
+       struct kvm_guest_msix_entry *guest_msix_entries;
        unsigned long irq_requested_type;
        int irq_source_id;
        int flags;
        struct pci_dev *dev;
        struct kvm *kvm;
+       spinlock_t assigned_dev_lock;
 };
 
 struct kvm_irq_mask_notifier {
@@ -360,6 +368,9 @@ void kvm_unregister_irq_ack_notifier(struct kvm_irq_ack_notifier *kian);
 int kvm_request_irq_source_id(struct kvm *kvm);
 void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id);
 
+/* For vcpu->arch.iommu_flags */
+#define KVM_IOMMU_CACHE_COHERENCY      0x1
+
 #ifdef CONFIG_IOMMU_API
 int kvm_iommu_map_pages(struct kvm *kvm, gfn_t base_gfn,
                        unsigned long npages);
index 2b8318c83e531d8dcf5cd6e96c09f994f12eef2a..fb46efbeabec6978365e33389d29c7f4b3d27e4a 100644 (file)
@@ -40,4 +40,31 @@ typedef unsigned long  hfn_t;
 
 typedef hfn_t pfn_t;
 
+union kvm_ioapic_redirect_entry {
+       u64 bits;
+       struct {
+               u8 vector;
+               u8 delivery_mode:3;
+               u8 dest_mode:1;
+               u8 delivery_status:1;
+               u8 polarity:1;
+               u8 remote_irr:1;
+               u8 trig_mode:1;
+               u8 mask:1;
+               u8 reserve:7;
+               u8 reserved[4];
+               u8 dest_id;
+       } fields;
+};
+
+struct kvm_lapic_irq {
+       u32 vector;
+       u32 delivery_mode;
+       u32 dest_mode;
+       u32 level;
+       u32 trig_mode;
+       u32 shorthand;
+       u32 dest_id;
+};
+
 #endif /* __KVM_TYPES_H__ */
index 40725447f5e0e958ef58097636603f00ca3d04e0..66c194e2d9b9c072fc201b864506ae12c010112d 100644 (file)
@@ -56,8 +56,7 @@ struct loop_device {
        gfp_t           old_gfp_mask;
 
        spinlock_t              lo_lock;
-       struct bio              *lo_bio;
-       struct bio              *lo_biotail;
+       struct bio_list         lo_bio_list;
        int                     lo_state;
        struct mutex            lo_ctl_mutex;
        struct task_struct      *lo_thread;
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h
new file mode 100644 (file)
index 0000000..e461b2c
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Common LSM logging functions
+ * Heavily borrowed from selinux/avc.h
+ *
+ * Author : Etienne BASSET  <etienne.basset@ensta.org>
+ *
+ * All credits to : Stephen Smalley, <sds@epoch.ncsc.mil>
+ * All BUGS to : Etienne BASSET  <etienne.basset@ensta.org>
+ */
+#ifndef _LSM_COMMON_LOGGING_
+#define _LSM_COMMON_LOGGING_
+
+#include <linux/stddef.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kdev_t.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/audit.h>
+#include <linux/in6.h>
+#include <linux/path.h>
+#include <linux/key.h>
+#include <linux/skbuff.h>
+#include <asm/system.h>
+
+
+/* Auxiliary data to use in generating the audit record. */
+struct common_audit_data {
+       char    type;
+#define LSM_AUDIT_DATA_FS      1
+#define LSM_AUDIT_DATA_NET     2
+#define LSM_AUDIT_DATA_CAP     3
+#define LSM_AUDIT_DATA_IPC     4
+#define LSM_AUDIT_DATA_TASK    5
+#define LSM_AUDIT_DATA_KEY     6
+       struct task_struct *tsk;
+       union   {
+               struct {
+                       struct path path;
+                       struct inode *inode;
+               } fs;
+               struct {
+                       int netif;
+                       struct sock *sk;
+                       u16 family;
+                       __be16 dport;
+                       __be16 sport;
+                       union {
+                               struct {
+                                       __be32 daddr;
+                                       __be32 saddr;
+                               } v4;
+                               struct {
+                                       struct in6_addr daddr;
+                                       struct in6_addr saddr;
+                               } v6;
+                       } fam;
+               } net;
+               int cap;
+               int ipc_id;
+               struct task_struct *tsk;
+#ifdef CONFIG_KEYS
+               struct {
+                       key_serial_t key;
+                       char *key_desc;
+               } key_struct;
+#endif
+       } u;
+       const char *function;
+       /* this union contains LSM specific data */
+       union {
+               /* SMACK data */
+               struct smack_audit_data {
+                       char *subject;
+                       char *object;
+                       char *request;
+                       int result;
+               } smack_audit_data;
+               /* SELinux data */
+               struct {
+                       u32 ssid;
+                       u32 tsid;
+                       u16 tclass;
+                       u32 requested;
+                       u32 audited;
+                       struct av_decision *avd;
+                       int result;
+               } selinux_audit_data;
+       } lsm_priv;
+       /* these callback will be implemented by a specific LSM */
+       void (*lsm_pre_audit)(struct audit_buffer *, void *);
+       void (*lsm_post_audit)(struct audit_buffer *, void *);
+};
+
+#define v4info fam.v4
+#define v6info fam.v6
+
+int ipv4_skb_to_auditdata(struct sk_buff *skb,
+               struct common_audit_data *ad, u8 *proto);
+
+int ipv6_skb_to_auditdata(struct sk_buff *skb,
+               struct common_audit_data *ad, u8 *proto);
+
+/* Initialize an LSM audit data structure. */
+#define COMMON_AUDIT_DATA_INIT(_d, _t) \
+       { memset((_d), 0, sizeof(struct common_audit_data)); \
+        (_d)->type = LSM_AUDIT_DATA_##_t; (_d)->function = __func__; }
+
+void common_lsm_audit(struct common_audit_data *a);
+
+#endif
index 5b4e28bcb788de92ffc3993c39e912f675a11c7f..927138cf30502c757f806b76471c86bb45466f5d 100644 (file)
@@ -9,6 +9,7 @@
 #define DEBUGFS_MAGIC          0x64626720
 #define SYSFS_MAGIC            0x62656572
 #define SECURITYFS_MAGIC       0x73636673
+#define SELINUX_MAGIC          0xf97cff8c
 #define TMPFS_MAGIC            0x01021994
 #define SQUASHFS_MAGIC         0x73717368
 #define EFS_SUPER_MAGIC                0x414A53
diff --git a/include/linux/mg_disk.h b/include/linux/mg_disk.h
deleted file mode 100644 (file)
index 1f76b1e..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- *  include/linux/mg_disk.c
- *
- *  Support for the mGine m[g]flash IO mode.
- *  Based on legacy hd.c
- *
- * (c) 2008 mGine Co.,LTD
- * (c) 2008 unsik Kim <donari75@gmail.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.
- */
-
-#ifndef __MG_DISK_H__
-#define __MG_DISK_H__
-
-#include <linux/blkdev.h>
-#include <linux/ata.h>
-
-/* name for block device */
-#define MG_DISK_NAME "mgd"
-/* name for platform device */
-#define MG_DEV_NAME "mg_disk"
-
-#define MG_DISK_MAJ 0
-#define MG_DISK_MAX_PART 16
-#define MG_SECTOR_SIZE 512
-#define MG_MAX_SECTS 256
-
-/* Register offsets */
-#define MG_BUFF_OFFSET                 0x8000
-#define MG_STORAGE_BUFFER_SIZE         0x200
-#define MG_REG_OFFSET                  0xC000
-#define MG_REG_FEATURE                 (MG_REG_OFFSET + 2)     /* write case */
-#define MG_REG_ERROR                   (MG_REG_OFFSET + 2)     /* read case */
-#define MG_REG_SECT_CNT                        (MG_REG_OFFSET + 4)
-#define MG_REG_SECT_NUM                        (MG_REG_OFFSET + 6)
-#define MG_REG_CYL_LOW                 (MG_REG_OFFSET + 8)
-#define MG_REG_CYL_HIGH                        (MG_REG_OFFSET + 0xA)
-#define MG_REG_DRV_HEAD                        (MG_REG_OFFSET + 0xC)
-#define MG_REG_COMMAND                 (MG_REG_OFFSET + 0xE)   /* write case */
-#define MG_REG_STATUS                  (MG_REG_OFFSET + 0xE)   /* read  case */
-#define MG_REG_DRV_CTRL                        (MG_REG_OFFSET + 0x10)
-#define MG_REG_BURST_CTRL              (MG_REG_OFFSET + 0x12)
-
-/* "Drive Select/Head Register" bit values */
-#define MG_REG_HEAD_MUST_BE_ON         0xA0 /* These 2 bits are always on */
-#define MG_REG_HEAD_DRIVE_MASTER       (0x00 | MG_REG_HEAD_MUST_BE_ON)
-#define MG_REG_HEAD_DRIVE_SLAVE                (0x10 | MG_REG_HEAD_MUST_BE_ON)
-#define MG_REG_HEAD_LBA_MODE           (0x40 | MG_REG_HEAD_MUST_BE_ON)
-
-
-/* "Device Control Register" bit values */
-#define MG_REG_CTRL_INTR_ENABLE                        0x0
-#define MG_REG_CTRL_INTR_DISABLE               (0x1<<1)
-#define MG_REG_CTRL_RESET                      (0x1<<2)
-#define MG_REG_CTRL_INTR_POLA_ACTIVE_HIGH      0x0
-#define MG_REG_CTRL_INTR_POLA_ACTIVE_LOW       (0x1<<4)
-#define MG_REG_CTRL_DPD_POLA_ACTIVE_LOW                0x0
-#define MG_REG_CTRL_DPD_POLA_ACTIVE_HIGH       (0x1<<5)
-#define MG_REG_CTRL_DPD_DISABLE                        0x0
-#define MG_REG_CTRL_DPD_ENABLE                 (0x1<<6)
-
-/* Status register bit */
-/* error bit in status register */
-#define MG_REG_STATUS_BIT_ERROR                        0x01
-/* corrected error in status register */
-#define MG_REG_STATUS_BIT_CORRECTED_ERROR      0x04
-/* data request bit in status register */
-#define MG_REG_STATUS_BIT_DATA_REQ             0x08
-/* DSC - Drive Seek Complete */
-#define MG_REG_STATUS_BIT_SEEK_DONE            0x10
-/* DWF - Drive Write Fault */
-#define MG_REG_STATUS_BIT_WRITE_FAULT          0x20
-#define MG_REG_STATUS_BIT_READY                        0x40
-#define MG_REG_STATUS_BIT_BUSY                 0x80
-
-/* handy status */
-#define MG_STAT_READY  (MG_REG_STATUS_BIT_READY | MG_REG_STATUS_BIT_SEEK_DONE)
-#define MG_READY_OK(s) (((s) & (MG_STAT_READY | \
-                               (MG_REG_STATUS_BIT_BUSY | \
-                                MG_REG_STATUS_BIT_WRITE_FAULT | \
-                                MG_REG_STATUS_BIT_ERROR))) == MG_STAT_READY)
-
-/* Error register */
-#define MG_REG_ERR_AMNF                0x01
-#define MG_REG_ERR_ABRT                0x04
-#define MG_REG_ERR_IDNF                0x10
-#define MG_REG_ERR_UNC         0x40
-#define MG_REG_ERR_BBK         0x80
-
-/* error code for others */
-#define MG_ERR_NONE            0
-#define MG_ERR_TIMEOUT         0x100
-#define MG_ERR_INIT_STAT       0x101
-#define MG_ERR_TRANSLATION     0x102
-#define MG_ERR_CTRL_RST                0x103
-#define MG_ERR_INV_STAT                0x104
-#define MG_ERR_RSTOUT          0x105
-
-#define MG_MAX_ERRORS  6       /* Max read/write errors */
-
-/* command */
-#define MG_CMD_RD 0x20
-#define MG_CMD_WR 0x30
-#define MG_CMD_SLEEP 0x99
-#define MG_CMD_WAKEUP 0xC3
-#define MG_CMD_ID 0xEC
-#define MG_CMD_WR_CONF 0x3C
-#define MG_CMD_RD_CONF 0x40
-
-/* operation mode */
-#define MG_OP_CASCADE (1 << 0)
-#define MG_OP_CASCADE_SYNC_RD (1 << 1)
-#define MG_OP_CASCADE_SYNC_WR (1 << 2)
-#define MG_OP_INTERLEAVE (1 << 3)
-
-/* synchronous */
-#define MG_BURST_LAT_4 (3 << 4)
-#define MG_BURST_LAT_5 (4 << 4)
-#define MG_BURST_LAT_6 (5 << 4)
-#define MG_BURST_LAT_7 (6 << 4)
-#define MG_BURST_LAT_8 (7 << 4)
-#define MG_BURST_LEN_4 (1 << 1)
-#define MG_BURST_LEN_8 (2 << 1)
-#define MG_BURST_LEN_16 (3 << 1)
-#define MG_BURST_LEN_32 (4 << 1)
-#define MG_BURST_LEN_CONT (0 << 1)
-
-/* timeout value (unit: ms) */
-#define MG_TMAX_CONF_TO_CMD    1
-#define MG_TMAX_WAIT_RD_DRQ    10
-#define MG_TMAX_WAIT_WR_DRQ    500
-#define MG_TMAX_RST_TO_BUSY    10
-#define MG_TMAX_HDRST_TO_RDY   500
-#define MG_TMAX_SWRST_TO_RDY   500
-#define MG_TMAX_RSTOUT         3000
-
-/* device attribution */
-/* use mflash as boot device */
-#define MG_BOOT_DEV            (1 << 0)
-/* use mflash as storage device */
-#define MG_STORAGE_DEV         (1 << 1)
-/* same as MG_STORAGE_DEV, but bootloader already done reset sequence */
-#define MG_STORAGE_DEV_SKIP_RST        (1 << 2)
-
-#define MG_DEV_MASK (MG_BOOT_DEV | MG_STORAGE_DEV | MG_STORAGE_DEV_SKIP_RST)
-
-/* names of GPIO resource */
-#define MG_RST_PIN     "mg_rst"
-/* except MG_BOOT_DEV, reset-out pin should be assigned */
-#define MG_RSTOUT_PIN  "mg_rstout"
-
-/* private driver data */
-struct mg_drv_data {
-       /* disk resource */
-       u32 use_polling;
-
-       /* device attribution */
-       u32 dev_attr;
-
-       /* internally used */
-       struct mg_host *host;
-};
-
-/* main structure for mflash driver */
-struct mg_host {
-       struct device *dev;
-
-       struct request_queue *breq;
-       spinlock_t lock;
-       struct gendisk *gd;
-
-       struct timer_list timer;
-       void (*mg_do_intr) (struct mg_host *);
-
-       u16 id[ATA_ID_WORDS];
-
-       u16 cyls;
-       u16 heads;
-       u16 sectors;
-       u32 n_sectors;
-       u32 nres_sectors;
-
-       void __iomem *dev_base;
-       unsigned int irq;
-       unsigned int rst;
-       unsigned int rstout;
-
-       u32 major;
-       u32 error;
-};
-
-/*
- * Debugging macro and defines
- */
-#undef DO_MG_DEBUG
-#ifdef DO_MG_DEBUG
-#  define MG_DBG(fmt, args...) \
-       printk(KERN_DEBUG "%s:%d "fmt, __func__, __LINE__, ##args)
-#else /* CONFIG_MG_DEBUG */
-#  define MG_DBG(fmt, args...) do { } while (0)
-#endif /* CONFIG_MG_DEBUG */
-
-#endif
index bff1f0d475c7593240d5a464ae8ecc7c03e07299..ad613ed66ab07b60e0f859eba21be6c6c4a1202e 100644 (file)
@@ -19,6 +19,7 @@ struct anon_vma;
 struct file_ra_state;
 struct user_struct;
 struct writeback_control;
+struct rlimit;
 
 #ifndef CONFIG_DISCONTIGMEM          /* Don't use mapnrs, do it properly */
 extern unsigned long max_mapnr;
@@ -580,12 +581,10 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
  */
 static inline unsigned long round_hint_to_min(unsigned long hint)
 {
-#ifdef CONFIG_SECURITY
        hint &= PAGE_MASK;
        if (((void *)hint != NULL) &&
            (hint < mmap_min_addr))
                return PAGE_ALIGN(mmap_min_addr);
-#endif
        return hint;
 }
 
@@ -1031,8 +1030,6 @@ extern void add_active_range(unsigned int nid, unsigned long start_pfn,
                                        unsigned long end_pfn);
 extern void remove_active_range(unsigned int nid, unsigned long start_pfn,
                                        unsigned long end_pfn);
-extern void push_node_boundaries(unsigned int nid, unsigned long start_pfn,
-                                       unsigned long end_pfn);
 extern void remove_all_active_ranges(void);
 extern unsigned long absent_pages_in_range(unsigned long start_pfn,
                                                unsigned long end_pfn);
@@ -1319,8 +1316,8 @@ int vmemmap_populate_basepages(struct page *start_page,
 int vmemmap_populate(struct page *start_page, unsigned long pages, int node);
 void vmemmap_populate_print_last(void);
 
-extern void *alloc_locked_buffer(size_t size);
-extern void free_locked_buffer(void *buffer, size_t size);
-extern void release_locked_buffer(void *buffer, size_t size);
+extern int account_locked_memory(struct mm_struct *mm, struct rlimit *rlim,
+                                size_t size);
+extern void refund_locked_memory(struct mm_struct *mm, size_t size);
 #endif /* __KERNEL__ */
 #endif /* _LINUX_MM_H */
index 3d1b7bde128361d0905bfbb6b28375c91d6465c3..97491f78b08cd72138ed25750145275ca1dabb90 100644 (file)
@@ -30,6 +30,8 @@ extern unsigned int kmmio_count;
 
 extern int register_kmmio_probe(struct kmmio_probe *p);
 extern void unregister_kmmio_probe(struct kmmio_probe *p);
+extern int kmmio_init(void);
+extern void kmmio_cleanup(void);
 
 #ifdef CONFIG_MMIOTRACE
 /* kmmio is active by some kmmio_probes? */
index 627ac082e2a64ad6734a665b270a3d11705e86d2..a8f2c0aa4c328af87718285f715bc72b19d7f55f 100644 (file)
@@ -337,6 +337,14 @@ struct module
        const char **trace_bprintk_fmt_start;
        unsigned int num_trace_bprintk_fmt;
 #endif
+#ifdef CONFIG_EVENT_TRACING
+       struct ftrace_event_call *trace_events;
+       unsigned int num_trace_events;
+#endif
+#ifdef CONFIG_FTRACE_MCOUNT_RECORD
+       unsigned long *ftrace_callsites;
+       unsigned int num_ftrace_callsites;
+#endif
 
 #ifdef CONFIG_MODULE_UNLOAD
        /* What modules depend on me? */
index 3069ec7e0ab84ca54a282c72d73385e44e69d63a..878cab4f5fcc5db95585184c22aea5d905a34295 100644 (file)
@@ -150,5 +150,6 @@ extern int __must_check mutex_lock_killable(struct mutex *lock);
  */
 extern int mutex_trylock(struct mutex *lock);
 extern void mutex_unlock(struct mutex *lock);
+extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
 
 #endif
index 0f71812d67d327283b551d2a3c84b762fa2617b4..d7d1c41a0b17db03da5768b35233f409b98b9b7d 100644 (file)
 #define PCI_DEVICE_ID_OXSEMI_PCIe952_1_U       0xC118
 #define PCI_DEVICE_ID_OXSEMI_PCIe952_1_GU      0xC11C
 #define PCI_DEVICE_ID_OXSEMI_16PCI954  0x9501
+#define PCI_DEVICE_ID_OXSEMI_C950      0x950B
 #define PCI_DEVICE_ID_OXSEMI_16PCI95N  0x9511
 #define PCI_DEVICE_ID_OXSEMI_16PCI954PP        0x9513
 #define PCI_DEVICE_ID_OXSEMI_16PCI952  0x9521
 #define PCI_DEVICE_ID_OXSEMI_16PCI952PP        0x9523
+#define PCI_SUBDEVICE_ID_OXSEMI_C950   0x0001
 
 #define PCI_VENDOR_ID_CHELSIO          0x1425
 
index c8f038554e80d1ecd18cd35c5a4305a30b90dd23..b43a9e0390591a9efe7612a8ba1af1dc13806a7b 100644 (file)
@@ -152,5 +152,6 @@ void generic_pipe_buf_unmap(struct pipe_inode_info *, struct pipe_buffer *, void
 void generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *);
 int generic_pipe_buf_confirm(struct pipe_inode_info *, struct pipe_buffer *);
 int generic_pipe_buf_steal(struct pipe_inode_info *, struct pipe_buffer *);
+void generic_pipe_buf_release(struct pipe_inode_info *, struct pipe_buffer *);
 
 #endif
index 67c15653fc230c9341ed1131c1e846156c6772bb..59e133d39d5091c4e5628212b4d563756fe02bec 100644 (file)
@@ -95,7 +95,6 @@ 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
 /* Returns 0 on success, -errno on denial. */
@@ -327,15 +326,6 @@ static inline void user_enable_block_step(struct task_struct *task)
 #define arch_ptrace_untrace(task)              do { } while (0)
 #endif
 
-#ifndef arch_ptrace_fork
-/*
- * Do machine-specific work to initialize a new task.
- *
- * This is called from copy_process().
- */
-#define arch_ptrace_fork(child, clone_flags)   do { } while (0)
-#endif
-
 extern int task_current_syscall(struct task_struct *target, long *callno,
                                unsigned long args[6], unsigned int maxargs,
                                unsigned long *sp, unsigned long *pc);
diff --git a/include/linux/rational.h b/include/linux/rational.h
new file mode 100644 (file)
index 0000000..4f532fc
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * rational fractions
+ *
+ * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <os@emlix.com>
+ *
+ * helper functions when coping with rational numbers,
+ * e.g. when calculating optimum numerator/denominator pairs for
+ * pll configuration taking into account restricted register size
+ */
+
+#ifndef _LINUX_RATIONAL_H
+#define _LINUX_RATIONAL_H
+
+void rational_best_approximation(
+       unsigned long given_numerator, unsigned long given_denominator,
+       unsigned long max_numerator, unsigned long max_denominator,
+       unsigned long *best_numerator, unsigned long *best_denominator);
+
+#endif /* _LINUX_RATIONAL_H */
index e649bd3f2c976c3f5bed58c067c351a336403e75..5710f43bbc9ec0aa42eabd74f851eda4a9a6f213 100644 (file)
@@ -198,6 +198,32 @@ static inline void list_splice_init_rcu(struct list_head *list,
        at->prev = last;
 }
 
+/**
+ * list_entry_rcu - get the struct for this entry
+ * @ptr:        the &struct list_head pointer.
+ * @type:       the type of the struct this is embedded in.
+ * @member:     the name of the list_struct within the struct.
+ *
+ * This primitive may safely run concurrently with the _rcu list-mutation
+ * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
+ */
+#define list_entry_rcu(ptr, type, member) \
+       container_of(rcu_dereference(ptr), type, member)
+
+/**
+ * list_first_entry_rcu - get the first element from a list
+ * @ptr:        the list head to take the element from.
+ * @type:       the type of the struct this is embedded in.
+ * @member:     the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ *
+ * This primitive may safely run concurrently with the _rcu list-mutation
+ * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
+ */
+#define list_first_entry_rcu(ptr, type, member) \
+       list_entry_rcu((ptr)->next, type, member)
+
 #define __list_for_each_rcu(pos, head) \
        for (pos = rcu_dereference((head)->next); \
                pos != (head); \
@@ -214,9 +240,9 @@ static inline void list_splice_init_rcu(struct list_head *list,
  * as long as the traversal is guarded by rcu_read_lock().
  */
 #define list_for_each_entry_rcu(pos, head, member) \
-       for (pos = list_entry(rcu_dereference((head)->next), typeof(*pos), member); \
+       for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                prefetch(pos->member.next), &pos->member != (head); \
-               pos = list_entry(rcu_dereference(pos->member.next), typeof(*pos), member))
+               pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
 
 
 /**
index 58b2aa5312b9caaae76f7f9dcb7e9cfcc7f06605..5a5153806c42562c730e8911099fea05c57bf4ad 100644 (file)
@@ -161,8 +161,15 @@ struct rcu_data {
        unsigned long offline_fqs;      /* Kicked due to being offline. */
        unsigned long resched_ipi;      /* Sent a resched IPI. */
 
-       /* 5) For future __rcu_pending statistics. */
+       /* 5) __rcu_pending() statistics. */
        long n_rcu_pending;             /* rcu_pending() calls since boot. */
+       long n_rp_qs_pending;
+       long n_rp_cb_ready;
+       long n_rp_cpu_needs_gp;
+       long n_rp_gp_completed;
+       long n_rp_gp_started;
+       long n_rp_need_fqs;
+       long n_rp_need_nothing;
 
        int cpu;
 };
index e1b7b2173885f8f14f4a8da3979d0a6eff08e186..8670f1575fe19abe7793b700aa70d525080c83bf 100644 (file)
@@ -11,7 +11,7 @@ struct ring_buffer_iter;
  * Don't refer to this struct directly, use functions below.
  */
 struct ring_buffer_event {
-       u32             type:2, len:3, time_delta:27;
+       u32             type_len:5, time_delta:27;
        u32             array[];
 };
 
@@ -24,7 +24,8 @@ struct ring_buffer_event {
  *                               size is variable depending on how much
  *                               padding is needed
  *                              If time_delta is non zero:
- *                               everything else same as RINGBUF_TYPE_DATA
+ *                               array[0] holds the actual length
+ *                               size = 4 + length (bytes)
  *
  * @RINGBUF_TYPE_TIME_EXTEND:  Extend the time delta
  *                              array[0] = time delta (28 .. 59)
@@ -35,22 +36,23 @@ struct ring_buffer_event {
  *                              array[1..2] = tv_sec
  *                              size = 16 bytes
  *
- * @RINGBUF_TYPE_DATA:         Data record
- *                              If len is zero:
+ * <= @RINGBUF_TYPE_DATA_TYPE_LEN_MAX:
+ *                             Data record
+ *                              If type_len is zero:
  *                               array[0] holds the actual length
  *                               array[1..(length+3)/4] holds data
- *                               size = 4 + 4 + length (bytes)
+ *                               size = 4 + length (bytes)
  *                              else
- *                               length = len << 2
+ *                               length = type_len << 2
  *                               array[0..(length+3)/4-1] holds data
  *                               size = 4 + length (bytes)
  */
 enum ring_buffer_type {
+       RINGBUF_TYPE_DATA_TYPE_LEN_MAX = 28,
        RINGBUF_TYPE_PADDING,
        RINGBUF_TYPE_TIME_EXTEND,
        /* FIXME: RINGBUF_TYPE_TIME_STAMP not implemented */
        RINGBUF_TYPE_TIME_STAMP,
-       RINGBUF_TYPE_DATA,
 };
 
 unsigned ring_buffer_event_length(struct ring_buffer_event *event);
@@ -68,13 +70,54 @@ ring_buffer_event_time_delta(struct ring_buffer_event *event)
        return event->time_delta;
 }
 
+/*
+ * ring_buffer_event_discard can discard any event in the ring buffer.
+ *   it is up to the caller to protect against a reader from
+ *   consuming it or a writer from wrapping and replacing it.
+ *
+ * No external protection is needed if this is called before
+ * the event is commited. But in that case it would be better to
+ * use ring_buffer_discard_commit.
+ *
+ * Note, if an event that has not been committed is discarded
+ * with ring_buffer_event_discard, it must still be committed.
+ */
 void ring_buffer_event_discard(struct ring_buffer_event *event);
 
+/*
+ * ring_buffer_discard_commit will remove an event that has not
+ *   ben committed yet. If this is used, then ring_buffer_unlock_commit
+ *   must not be called on the discarded event. This function
+ *   will try to remove the event from the ring buffer completely
+ *   if another event has not been written after it.
+ *
+ * Example use:
+ *
+ *  if (some_condition)
+ *    ring_buffer_discard_commit(buffer, event);
+ *  else
+ *    ring_buffer_unlock_commit(buffer, event);
+ */
+void ring_buffer_discard_commit(struct ring_buffer *buffer,
+                               struct ring_buffer_event *event);
+
 /*
  * size is in bytes for each per CPU buffer.
  */
 struct ring_buffer *
-ring_buffer_alloc(unsigned long size, unsigned flags);
+__ring_buffer_alloc(unsigned long size, unsigned flags, struct lock_class_key *key);
+
+/*
+ * Because the ring buffer is generic, if other users of the ring buffer get
+ * traced by ftrace, it can produce lockdep warnings. We need to keep each
+ * ring buffer's lock class separate.
+ */
+#define ring_buffer_alloc(size, flags)                 \
+({                                                     \
+       static struct lock_class_key __key;             \
+       __ring_buffer_alloc((size), (flags), &__key);   \
+})
+
 void ring_buffer_free(struct ring_buffer *buffer);
 
 int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size);
@@ -122,6 +165,8 @@ unsigned long ring_buffer_entries(struct ring_buffer *buffer);
 unsigned long ring_buffer_overruns(struct ring_buffer *buffer);
 unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu);
 unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu);
+unsigned long ring_buffer_commit_overrun_cpu(struct ring_buffer *buffer, int cpu);
+unsigned long ring_buffer_nmi_dropped_cpu(struct ring_buffer *buffer, int cpu);
 
 u64 ring_buffer_time_stamp(struct ring_buffer *buffer, int cpu);
 void ring_buffer_normalize_time_stamp(struct ring_buffer *buffer,
@@ -137,6 +182,11 @@ void ring_buffer_free_read_page(struct ring_buffer *buffer, void *data);
 int ring_buffer_read_page(struct ring_buffer *buffer, void **data_page,
                          size_t len, int cpu, int full);
 
+struct trace_seq;
+
+int ring_buffer_print_entry_header(struct trace_seq *s);
+int ring_buffer_print_page_header(struct trace_seq *s);
+
 enum ring_buffer_flags {
        RB_FL_OVERWRITE         = 1 << 0,
 };
index b4c38bc8049cbbea17e0ca4f929f35df9cddbe1f..42bf2766111e5585f24812fbc7183d81316b8f62 100644 (file)
@@ -77,6 +77,7 @@ struct sched_param {
 #include <linux/proportions.h>
 #include <linux/seccomp.h>
 #include <linux/rcupdate.h>
+#include <linux/rculist.h>
 #include <linux/rtmutex.h>
 
 #include <linux/time.h>
@@ -96,8 +97,8 @@ struct exec_domain;
 struct futex_pi_state;
 struct robust_list_head;
 struct bio;
-struct bts_tracer;
 struct fs_struct;
+struct bts_context;
 
 /*
  * List of flags we want to share for kernel threads,
@@ -116,6 +117,7 @@ struct fs_struct;
  *    11 bit fractions.
  */
 extern unsigned long avenrun[];                /* Load averages */
+extern void get_avenrun(unsigned long *loads, unsigned long offset, int shift);
 
 #define FSHIFT         11              /* nr of bits of precision */
 #define FIXED_1                (1<<FSHIFT)     /* 1.0 as fixed-point */
@@ -135,8 +137,8 @@ DECLARE_PER_CPU(unsigned long, process_counts);
 extern int nr_processes(void);
 extern unsigned long nr_running(void);
 extern unsigned long nr_uninterruptible(void);
-extern unsigned long nr_active(void);
 extern unsigned long nr_iowait(void);
+extern void calc_global_load(void);
 
 extern unsigned long get_parent_ip(unsigned long addr);
 
@@ -838,7 +840,17 @@ struct sched_group {
         */
        u32 reciprocal_cpu_power;
 
-       unsigned long cpumask[];
+       /*
+        * The CPUs this group covers.
+        *
+        * NOTE: this field is variable length. (Allocated dynamically
+        * by attaching extra space to the end of the structure,
+        * depending on how many CPUs the kernel has booted up with)
+        *
+        * It is also be embedded into static data structures at build
+        * time. (See 'struct static_sched_group' in kernel/sched.c)
+        */
+       unsigned long cpumask[0];
 };
 
 static inline struct cpumask *sched_group_cpus(struct sched_group *sg)
@@ -924,8 +936,17 @@ struct sched_domain {
        char *name;
 #endif
 
-       /* span of all CPUs in this domain */
-       unsigned long span[];
+       /*
+        * Span of all CPUs in this domain.
+        *
+        * NOTE: this field is variable length. (Allocated dynamically
+        * by attaching extra space to the end of the structure,
+        * depending on how many CPUs the kernel has booted up with)
+        *
+        * It is also be embedded into static data structures at build
+        * time. (See 'struct static_sched_domain' in kernel/sched.c)
+        */
+       unsigned long span[0];
 };
 
 static inline struct cpumask *sched_domain_span(struct sched_domain *sd)
@@ -1209,18 +1230,11 @@ struct task_struct {
        struct list_head ptraced;
        struct list_head ptrace_entry;
 
-#ifdef CONFIG_X86_PTRACE_BTS
        /*
         * This is the tracer handle for the ptrace BTS extension.
         * This field actually belongs to the ptracer task.
         */
-       struct bts_tracer *bts;
-       /*
-        * The buffer to hold the BTS data.
-        */
-       void *bts_buffer;
-       size_t bts_size;
-#endif /* CONFIG_X86_PTRACE_BTS */
+       struct bts_context *bts;
 
        /* PID/PID hash table linkage. */
        struct pid_link pids[PIDTYPE_MAX];
@@ -1247,7 +1261,9 @@ struct task_struct {
                                         * credentials (COW) */
        const struct cred *cred;        /* effective (overridable) subjective task
                                         * credentials (COW) */
-       struct mutex cred_exec_mutex;   /* execve vs ptrace cred calculation mutex */
+       struct mutex cred_guard_mutex;  /* guard against foreign influences on
+                                        * credential calculations
+                                        * (notably. ptrace) */
 
        char comm[TASK_COMM_LEN]; /* executable name excluding path
                                     - access with [gs]et_task_comm (which lock
@@ -1428,7 +1444,9 @@ struct task_struct {
 #ifdef CONFIG_TRACING
        /* state flags for use by tracers */
        unsigned long trace;
-#endif
+       /* bitmask of trace recursion */
+       unsigned long trace_recursion;
+#endif /* CONFIG_TRACING */
 };
 
 /* Future-safe accessor for struct task_struct's cpus_allowed. */
@@ -1885,6 +1903,7 @@ extern void sched_dead(struct task_struct *p);
 
 extern void proc_caches_init(void);
 extern void flush_signals(struct task_struct *);
+extern void __flush_signals(struct task_struct *);
 extern void ignore_signals(struct task_struct *);
 extern void flush_signal_handlers(struct task_struct *, int force_default);
 extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info);
@@ -2001,8 +2020,10 @@ extern void set_task_comm(struct task_struct *tsk, char *from);
 extern char *get_task_comm(char *to, struct task_struct *tsk);
 
 #ifdef CONFIG_SMP
+extern void wait_task_context_switch(struct task_struct *p);
 extern unsigned long wait_task_inactive(struct task_struct *, long match_state);
 #else
+static inline void wait_task_context_switch(struct task_struct *p) {}
 static inline unsigned long wait_task_inactive(struct task_struct *p,
                                               long match_state)
 {
@@ -2010,7 +2031,8 @@ static inline unsigned long wait_task_inactive(struct task_struct *p,
 }
 #endif
 
-#define next_task(p)   list_entry(rcu_dereference((p)->tasks.next), struct task_struct, tasks)
+#define next_task(p) \
+       list_entry_rcu((p)->tasks.next, struct task_struct, tasks)
 
 #define for_each_process(p) \
        for (p = &init_task ; (p = next_task(p)) != &init_task ; )
@@ -2049,8 +2071,8 @@ int same_thread_group(struct task_struct *p1, struct task_struct *p2)
 
 static inline struct task_struct *next_thread(const struct task_struct *p)
 {
-       return list_entry(rcu_dereference(p->thread_group.next),
-                         struct task_struct, thread_group);
+       return list_entry_rcu(p->thread_group.next,
+                             struct task_struct, thread_group);
 }
 
 static inline int thread_group_empty(struct task_struct *p)
index d5fd6163606fa028f7db538825cc055a051e0d51..5eff459b38338ace06bb7d9e83d10a462b906203 100644 (file)
@@ -2197,6 +2197,8 @@ static inline int security_file_mmap(struct file *file, unsigned long reqprot,
                                     unsigned long addr,
                                     unsigned long addr_only)
 {
+       if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO))
+               return -EACCES;
        return 0;
 }
 
index 9136cc5608c3df2b15145ab7f1fbe09c966fd8f9..e5bb75a6380219256c52dce6c75be8aebddb2aaf 100644 (file)
@@ -96,54 +96,76 @@ struct serial_uart_config {
 
 /*
  * Definitions for async_struct (and serial_struct) flags field
+ *
+ * Define ASYNCB_* for convenient use with {test,set,clear}_bit.
  */
-#define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
-                                  on the callout port */
-#define ASYNC_FOURPORT  0x0002 /* Set OU1, OUT2 per AST Fourport settings */
-#define ASYNC_SAK      0x0004  /* Secure Attention Key (Orange book) */
-#define ASYNC_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define ASYNC_SPD_MASK 0x1030
-#define ASYNC_SPD_HI   0x0010  /* Use 56000 instead of 38400 bps */
-
-#define ASYNC_SPD_VHI  0x0020  /* Use 115200 instead of 38400 bps */
-#define ASYNC_SPD_CUST 0x0030  /* Use user-specified divisor */
-
-#define ASYNC_SKIP_TEST        0x0040 /* Skip UART test during autoconfiguration */
-#define ASYNC_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
-#define ASYNC_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define ASYNC_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
-#define ASYNC_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
-
-#define ASYNC_HARDPPS_CD       0x0800  /* Call hardpps when CD goes high  */
-
-#define ASYNC_SPD_SHI  0x1000  /* Use 230400 instead of 38400 bps */
-#define ASYNC_SPD_WARP 0x1010  /* Use 460800 instead of 38400 bps */
-
-#define ASYNC_LOW_LATENCY 0x2000 /* Request low latency behaviour */
-
-#define ASYNC_BUGGY_UART  0x4000 /* This is a buggy UART, skip some safety
-                                 * checks.  Note: can be dangerous! */
-
-#define ASYNC_AUTOPROBE         0x8000 /* Port was autoprobed by PCI or PNP code */
-
-#define ASYNC_FLAGS    0x7FFF  /* Possible legal async flags */
-#define ASYNC_USR_MASK 0x3430  /* Legal flags that non-privileged
-                                * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define ASYNC_INITIALIZED      0x80000000 /* Serial port was initialized */
-#define ASYNC_NORMAL_ACTIVE    0x20000000 /* Normal device is active */
-#define ASYNC_BOOT_AUTOCONF    0x10000000 /* Autoconfigure port on bootup */
-#define ASYNC_CLOSING          0x08000000 /* Serial port is closing */
-#define ASYNC_CTS_FLOW         0x04000000 /* Do CTS flow control */
-#define ASYNC_CHECK_CD         0x02000000 /* i.e., CLOCAL */
-#define ASYNC_SHARE_IRQ                0x01000000 /* for multifunction cards
-                                            --- no longer used */
-#define ASYNC_CONS_FLOW                0x00800000 /* flow control for console  */
-
-#define ASYNC_BOOT_ONLYMCA     0x00400000 /* Probe only if MCA bus */
-#define ASYNC_INTERNAL_FLAGS   0xFFC00000 /* Internal flags */
+#define ASYNCB_HUP_NOTIFY       0 /* Notify getty on hangups and closes
+                                   * on the callout port */
+#define ASYNCB_FOURPORT                 1 /* Set OU1, OUT2 per AST Fourport settings */
+#define ASYNCB_SAK              2 /* Secure Attention Key (Orange book) */
+#define ASYNCB_SPLIT_TERMIOS    3 /* Separate termios for dialin/callout */
+#define ASYNCB_SPD_HI           4 /* Use 56000 instead of 38400 bps */
+#define ASYNCB_SPD_VHI          5 /* Use 115200 instead of 38400 bps */
+#define ASYNCB_SKIP_TEST        6 /* Skip UART test during autoconfiguration */
+#define ASYNCB_AUTO_IRQ                 7 /* Do automatic IRQ during
+                                   * autoconfiguration */
+#define ASYNCB_SESSION_LOCKOUT  8 /* Lock out cua opens based on session */
+#define ASYNCB_PGRP_LOCKOUT     9 /* Lock out cua opens based on pgrp */
+#define ASYNCB_CALLOUT_NOHUP   10 /* Don't do hangups for cua device */
+#define ASYNCB_HARDPPS_CD      11 /* Call hardpps when CD goes high  */
+#define ASYNCB_SPD_SHI         12 /* Use 230400 instead of 38400 bps */
+#define ASYNCB_LOW_LATENCY     13 /* Request low latency behaviour */
+#define ASYNCB_BUGGY_UART      14 /* This is a buggy UART, skip some safety
+                                   * checks.  Note: can be dangerous! */
+#define ASYNCB_AUTOPROBE       15 /* Port was autoprobed by PCI or PNP code */
+#define ASYNCB_LAST_USER       15
+
+/* Internal flags used only by kernel */
+#define ASYNCB_INITIALIZED     31 /* Serial port was initialized */
+#define ASYNCB_NORMAL_ACTIVE   29 /* Normal device is active */
+#define ASYNCB_BOOT_AUTOCONF   28 /* Autoconfigure port on bootup */
+#define ASYNCB_CLOSING         27 /* Serial port is closing */
+#define ASYNCB_CTS_FLOW                26 /* Do CTS flow control */
+#define ASYNCB_CHECK_CD                25 /* i.e., CLOCAL */
+#define ASYNCB_SHARE_IRQ       24 /* for multifunction cards, no longer used */
+#define ASYNCB_CONS_FLOW       23 /* flow control for console  */
+#define ASYNCB_BOOT_ONLYMCA    22 /* Probe only if MCA bus */
+#define ASYNCB_FIRST_KERNEL    22
+
+#define ASYNC_HUP_NOTIFY       (1U << ASYNCB_HUP_NOTIFY)
+#define ASYNC_FOURPORT         (1U << ASYNCB_FOURPORT)
+#define ASYNC_SAK              (1U << ASYNCB_SAK)
+#define ASYNC_SPLIT_TERMIOS    (1U << ASYNCB_SPLIT_TERMIOS)
+#define ASYNC_SPD_HI           (1U << ASYNCB_SPD_HI)
+#define ASYNC_SPD_VHI          (1U << ASYNCB_SPD_VHI)
+#define ASYNC_SKIP_TEST                (1U << ASYNCB_SKIP_TEST)
+#define ASYNC_AUTO_IRQ         (1U << ASYNCB_AUTO_IRQ)
+#define ASYNC_SESSION_LOCKOUT  (1U << ASYNCB_SESSION_LOCKOUT)
+#define ASYNC_PGRP_LOCKOUT     (1U << ASYNCB_PGRP_LOCKOUT)
+#define ASYNC_CALLOUT_NOHUP    (1U << ASYNCB_CALLOUT_NOHUP)
+#define ASYNC_HARDPPS_CD       (1U << ASYNCB_HARDPPS_CD)
+#define ASYNC_SPD_SHI          (1U << ASYNCB_SPD_SHI)
+#define ASYNC_LOW_LATENCY      (1U << ASYNCB_LOW_LATENCY)
+#define ASYNC_BUGGY_UART       (1U << ASYNCB_BUGGY_UART)
+#define ASYNC_AUTOPROBE                (1U << ASYNCB_AUTOPROBE)
+
+#define ASYNC_FLAGS            ((1U << ASYNCB_LAST_USER) - 1)
+#define ASYNC_USR_MASK         (ASYNC_SPD_HI|ASYNC_SPD_VHI| \
+               ASYNC_CALLOUT_NOHUP|ASYNC_SPD_SHI|ASYNC_LOW_LATENCY)
+#define ASYNC_SPD_CUST         (ASYNC_SPD_HI|ASYNC_SPD_VHI)
+#define ASYNC_SPD_WARP         (ASYNC_SPD_HI|ASYNC_SPD_SHI)
+#define ASYNC_SPD_MASK         (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI)
+
+#define ASYNC_INITIALIZED      (1U << ASYNCB_INITIALIZED)
+#define ASYNC_NORMAL_ACTIVE    (1U << ASYNCB_NORMAL_ACTIVE)
+#define ASYNC_BOOT_AUTOCONF    (1U << ASYNCB_BOOT_AUTOCONF)
+#define ASYNC_CLOSING          (1U << ASYNCB_CLOSING)
+#define ASYNC_CTS_FLOW         (1U << ASYNCB_CTS_FLOW)
+#define ASYNC_CHECK_CD         (1U << ASYNCB_CHECK_CD)
+#define ASYNC_SHARE_IRQ                (1U << ASYNCB_SHARE_IRQ)
+#define ASYNC_CONS_FLOW                (1U << ASYNCB_CONS_FLOW)
+#define ASYNC_BOOT_ONLYMCA     (1U << ASYNCB_BOOT_ONLYMCA)
+#define ASYNC_INTERNAL_FLAGS   (~((1U << ASYNCB_FIRST_KERNEL) - 1))
 
 /*
  * Multiport serial configuration structure --- external structure
index 57a97e52e58d0339d0e3dfd1271e143e865d68a4..6fd80c4243f1bd089d8356d7ed0e181ed911753e 100644 (file)
@@ -41,7 +41,8 @@
 #define PORT_XSCALE    15
 #define PORT_RM9000    16      /* PMC-Sierra RM9xxx internal UART */
 #define PORT_OCTEON    17      /* Cavium OCTEON internal UART */
-#define PORT_MAX_8250  17      /* max port ID */
+#define PORT_AR7       18      /* Texas Instruments AR7 internal UART */
+#define PORT_MAX_8250  18      /* max port ID */
 
 /*
  * ARM specific type numbers.  These are not currently guaranteed
 /* MAX3100 */
 #define PORT_MAX3100    86
 
+/* Timberdale UART */
+#define PORT_TIMBUART  87
+
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
index 893cc53486bc676a99ed2712fd220c66623f0814..1c297ddc9d5a4ef50895e9199ca7bf6fcb411182 100644 (file)
@@ -25,8 +25,7 @@ struct plat_sci_port {
        unsigned int    irqs[SCIx_NR_IRQS];     /* ERI, RXI, TXI, BRI */
        unsigned int    type;                   /* SCI / SCIF / IRDA */
        upf_t           flags;                  /* UPF_* flags */
+       char            *clk;                   /* clock string */
 };
 
-int early_sci_setup(struct uart_port *port);
-
 #endif /* __LINUX_SERIAL_SCI_H */
diff --git a/include/linux/sh_cmt.h b/include/linux/sh_cmt.h
deleted file mode 100644 (file)
index 68cacde..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __SH_CMT_H__
-#define __SH_CMT_H__
-
-struct sh_cmt_config {
-       char *name;
-       unsigned long channel_offset;
-       int timer_bit;
-       char *clk;
-       unsigned long clockevent_rating;
-       unsigned long clocksource_rating;
-};
-
-#endif /* __SH_CMT_H__ */
diff --git a/include/linux/sh_timer.h b/include/linux/sh_timer.h
new file mode 100644 (file)
index 0000000..864bd56
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __SH_TIMER_H__
+#define __SH_TIMER_H__
+
+struct sh_timer_config {
+       char *name;
+       long channel_offset;
+       int timer_bit;
+       char *clk;
+       unsigned long clockevent_rating;
+       unsigned long clocksource_rating;
+};
+
+#endif /* __SH_TIMER_H__ */
index 84f997f8aa53cfcc8b04ff86bb4b0263f0e7dc1a..c7552836bd954a0f0a0235feea5cf9acb5c1a2c8 100644 (file)
@@ -235,6 +235,8 @@ static inline int valid_signal(unsigned long sig)
 extern int next_signal(struct sigpending *pending, sigset_t *mask);
 extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p);
 extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
+extern long do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig,
+                                siginfo_t *info);
 extern long do_sigpending(void __user *, unsigned long);
 extern int sigprocmask(int, sigset_t *, sigset_t *);
 extern int show_unhandled_signals;
index 5ac9b0bcaf9adef1fdfddebd2aff6290a44f7b9f..713f841ecaa914e74aead8e4d8ff5d74cb5040d3 100644 (file)
@@ -14,7 +14,7 @@
 #include <asm/page.h>          /* kmalloc_sizes.h needs PAGE_SIZE */
 #include <asm/cache.h>         /* kmalloc_sizes.h needs L1_CACHE_BYTES */
 #include <linux/compiler.h>
-#include <trace/kmemtrace.h>
+#include <linux/kmemtrace.h>
 
 /* Size description struct for general caches. */
 struct cache_sizes {
index 5046f90c11710178127a20a7bcb8677b4e80d943..be5d40c43bd2e7aa96264e624b074f4a884826f4 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/gfp.h>
 #include <linux/workqueue.h>
 #include <linux/kobject.h>
-#include <trace/kmemtrace.h>
+#include <linux/kmemtrace.h>
 
 enum stat_item {
        ALLOC_FASTPATH,         /* Allocation from cpu slab */
index 938234c4a996ba6e78521ffc60ecc197034fed9d..d4841ed8215b755ae2a291245687187479d4d27c 100644 (file)
@@ -60,6 +60,7 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock)
 #define __raw_spin_is_locked(lock)     ((void)(lock), 0)
 /* for sched.c and kernel_lock.c: */
 # define __raw_spin_lock(lock)         do { (void)(lock); } while (0)
+# define __raw_spin_lock_flags(lock, flags)    do { (void)(lock); } while (0)
 # define __raw_spin_unlock(lock)       do { (void)(lock); } while (0)
 # define __raw_spin_trylock(lock)      ({ (void)(lock); 1; })
 #endif /* DEBUG_SPINLOCK */
index 5f3faa9d15aea2416804080e1e5d17cfc9b5b5ce..18e7c7c0cae6d2d7733518d3f740a1d0011b201c 100644 (file)
@@ -11,8 +11,7 @@
 #include <linux/pipe_fs_i.h>
 
 /*
- * splice is tied to pipes as a transport (at least for now), so we'll just
- * add the splice flags here.
+ * Flags passed in from splice/tee/vmsplice
  */
 #define SPLICE_F_MOVE  (0x01)  /* move pages instead of copying */
 #define SPLICE_F_NONBLOCK (0x02) /* don't block on the pipe splicing (but */
index ac9ff54f7cb305943e5444f27be83460ef398206..cb1a6631b8f449bcf2738f37208783dd23be87ba 100644 (file)
@@ -29,7 +29,8 @@ extern void *swiotlb_alloc(unsigned order, unsigned long nslabs);
 
 extern dma_addr_t swiotlb_phys_to_bus(struct device *hwdev,
                                      phys_addr_t address);
-extern phys_addr_t swiotlb_bus_to_phys(dma_addr_t address);
+extern phys_addr_t swiotlb_bus_to_phys(struct device *hwdev,
+                                      dma_addr_t address);
 
 extern int swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size);
 
index e6b820f8b56b8ae3bf50ac980d1e95ce3ad6536e..a8cc4e13434c4261ae8ab536566b23fcd777286a 100644 (file)
@@ -21,13 +21,14 @@ struct restart_block {
                struct {
                        unsigned long arg0, arg1, arg2, arg3;
                };
-               /* For futex_wait */
+               /* For futex_wait and futex_wait_requeue_pi */
                struct {
                        u32 *uaddr;
                        u32 val;
                        u32 flags;
                        u32 bitset;
                        u64 time;
+                       u32 *uaddr2;
                } futex;
                /* For nanosleep */
                struct {
index 242f62499bb7bca6cd6c58fe134e7ffb8e97fa19..ea16c1a01d5188b3d9d39181d993d0c92508923b 100644 (file)
@@ -113,6 +113,21 @@ struct timespec current_kernel_time(void);
 #define CURRENT_TIME           (current_kernel_time())
 #define CURRENT_TIME_SEC       ((struct timespec) { get_seconds(), 0 })
 
+/* Some architectures do not supply their own clocksource.
+ * This is mainly the case in architectures that get their
+ * inter-tick times by reading the counter on their interval
+ * timer. Since these timers wrap every tick, they're not really
+ * useful as clocksources. Wrapping them to act like one is possible
+ * but not very efficient. So we provide a callout these arches
+ * can implement for use with the jiffies clocksource to provide
+ * finer then tick granular time.
+ */
+#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
+extern u32 arch_gettimeoffset(void);
+#else
+static inline u32 arch_gettimeoffset(void) { return 0; }
+#endif
+
 extern void do_gettimeofday(struct timeval *tv);
 extern int do_settimeofday(struct timespec *tv);
 extern int do_sys_settimeofday(struct timespec *tv, struct timezone *tz);
diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h
new file mode 100644 (file)
index 0000000..c68bccb
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef _LINUX_TRACE_SEQ_H
+#define _LINUX_TRACE_SEQ_H
+
+#include <linux/fs.h>
+
+/*
+ * Trace sequences are used to allow a function to call several other functions
+ * to create a string of data to use (up to a max of PAGE_SIZE.
+ */
+
+struct trace_seq {
+       unsigned char           buffer[PAGE_SIZE];
+       unsigned int            len;
+       unsigned int            readpos;
+};
+
+static inline void
+trace_seq_init(struct trace_seq *s)
+{
+       s->len = 0;
+       s->readpos = 0;
+}
+
+/*
+ * Currently only defined when tracing is enabled.
+ */
+#ifdef CONFIG_TRACING
+extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
+       __attribute__ ((format (printf, 2, 3)));
+extern int trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
+       __attribute__ ((format (printf, 2, 0)));
+extern int
+trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary);
+extern void trace_print_seq(struct seq_file *m, struct trace_seq *s);
+extern ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf,
+                                size_t cnt);
+extern int trace_seq_puts(struct trace_seq *s, const char *str);
+extern int trace_seq_putc(struct trace_seq *s, unsigned char c);
+extern int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len);
+extern int trace_seq_putmem_hex(struct trace_seq *s, const void *mem,
+                               size_t len);
+extern void *trace_seq_reserve(struct trace_seq *s, size_t len);
+extern int trace_seq_path(struct trace_seq *s, struct path *path);
+
+#else /* CONFIG_TRACING */
+static inline int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
+{
+       return 0;
+}
+static inline int
+trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary)
+{
+       return 0;
+}
+
+static inline void trace_print_seq(struct seq_file *m, struct trace_seq *s)
+{
+}
+static inline ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf,
+                                size_t cnt)
+{
+       return 0;
+}
+static inline int trace_seq_puts(struct trace_seq *s, const char *str)
+{
+       return 0;
+}
+static inline int trace_seq_putc(struct trace_seq *s, unsigned char c)
+{
+       return 0;
+}
+static inline int
+trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len)
+{
+       return 0;
+}
+static inline int trace_seq_putmem_hex(struct trace_seq *s, const void *mem,
+                                      size_t len)
+{
+       return 0;
+}
+static inline void *trace_seq_reserve(struct trace_seq *s, size_t len)
+{
+       return NULL;
+}
+static inline int trace_seq_path(struct trace_seq *s, struct path *path)
+{
+       return 0;
+}
+#endif /* CONFIG_TRACING */
+
+#endif /* _LINUX_TRACE_SEQ_H */
index d35a7ee7611fe1025ed5ccaf01c6ea614c03d688..14df7e635d439e07d438e9890f0c8f718fa2aa15 100644 (file)
@@ -31,6 +31,8 @@ struct tracepoint {
                                         * Keep in sync with vmlinux.lds.h.
                                         */
 
+#ifndef DECLARE_TRACE
+
 #define TP_PROTO(args...)      args
 #define TP_ARGS(args...)               args
 
@@ -114,6 +116,7 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin,
        struct tracepoint *end)
 { }
 #endif /* CONFIG_TRACEPOINTS */
+#endif /* DECLARE_TRACE */
 
 /*
  * Connect a probe to a tracepoint.
@@ -154,10 +157,8 @@ static inline void tracepoint_synchronize_unregister(void)
 }
 
 #define PARAMS(args...) args
-#define TRACE_FORMAT(name, proto, args, fmt)           \
-       DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
-
 
+#ifndef TRACE_EVENT
 /*
  * For use with the TRACE_EVENT macro:
  *
@@ -262,5 +263,6 @@ static inline void tracepoint_synchronize_unregister(void)
 
 #define TRACE_EVENT(name, proto, args, struct, assign, print)  \
        DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
+#endif
 
 #endif
index fc39db95499fbab4142800b24faf52b182fae113..1488d8c81aac6587c9edc8002f39f89d104391cf 100644 (file)
@@ -185,7 +185,7 @@ struct tty_port;
 struct tty_port_operations {
        /* Return 1 if the carrier is raised */
        int (*carrier_raised)(struct tty_port *port);
-       void (*raise_dtr_rts)(struct tty_port *port);
+       void (*dtr_rts)(struct tty_port *port, int raise);
 };
        
 struct tty_port {
@@ -201,6 +201,9 @@ struct tty_port {
        unsigned char           *xmit_buf;      /* Optional buffer */
        int                     close_delay;    /* Close port delay */
        int                     closing_wait;   /* Delay for output */
+       int                     drain_delay;    /* Set to zero if no pure time
+                                                  based drain is needed else
+                                                  set to size of fifo */
 };
 
 /*
@@ -223,8 +226,11 @@ struct tty_struct {
        struct tty_driver *driver;
        const struct tty_operations *ops;
        int index;
-       /* The ldisc objects are protected by tty_ldisc_lock at the moment */
-       struct tty_ldisc ldisc;
+
+       /* Protects ldisc changes: Lock tty not pty */
+       struct mutex ldisc_mutex;
+       struct tty_ldisc *ldisc;
+
        struct mutex termios_mutex;
        spinlock_t ctrl_lock;
        /* Termios values are protected by the termios mutex */
@@ -311,6 +317,7 @@ struct tty_struct {
 #define TTY_CLOSING            7       /* ->close() in progress */
 #define TTY_LDISC              9       /* Line discipline attached */
 #define TTY_LDISC_CHANGING     10      /* Line discipline changing */
+#define TTY_LDISC_OPEN         11      /* Line discipline is open */
 #define TTY_HW_COOK_OUT        14      /* Hardware can do output cooking */
 #define TTY_HW_COOK_IN                 15      /* Hardware can do input cooking */
 #define TTY_PTY_LOCK           16      /* pty private */
@@ -403,6 +410,7 @@ extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b);
 extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
 extern void tty_ldisc_deref(struct tty_ldisc *);
 extern struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *);
+extern void tty_ldisc_hangup(struct tty_struct *tty);
 extern const struct file_operations tty_ldiscs_proc_fops;
 
 extern void tty_wakeup(struct tty_struct *tty);
@@ -425,6 +433,9 @@ extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
 extern void tty_release_dev(struct file *filp);
 extern int tty_init_termios(struct tty_struct *tty);
 
+extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty);
+extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty);
+
 extern struct mutex tty_mutex;
 
 extern void tty_write_unlock(struct tty_struct *tty);
@@ -438,6 +449,7 @@ extern struct tty_struct *tty_port_tty_get(struct tty_port *port);
 extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
 extern int tty_port_carrier_raised(struct tty_port *port);
 extern void tty_port_raise_dtr_rts(struct tty_port *port);
+extern void tty_port_lower_dtr_rts(struct tty_port *port);
 extern void tty_port_hangup(struct tty_port *port);
 extern int tty_port_block_til_ready(struct tty_port *port,
                                struct tty_struct *tty, struct file *filp);
index bcba84ea2d86ae280a2778ebcce9dc617c0b7e9c..3566129384a4d77e83d6496db87ea456eca2e9f6 100644 (file)
  *     the line discipline are close to full, and it should somehow
  *     signal that no more characters should be sent to the tty.
  *
- *     Optional: Always invoke via tty_throttle();
+ *     Optional: Always invoke via tty_throttle(), called under the
+ *     termios lock.
  * 
  * void (*unthrottle)(struct tty_struct * tty);
  *
  *     that characters can now be sent to the tty without fear of
  *     overrunning the input buffers of the line disciplines.
  * 
- *     Optional: Always invoke via tty_unthrottle();
+ *     Optional: Always invoke via tty_unthrottle(), called under the
+ *     termios lock.
  *
  * void (*stop)(struct tty_struct *tty);
  *
index 625e9e4639c68f3e9fc2b6b1d3ce4a734fa2113b..8cdfed738fe4b8b28d0f7208c8553f0cf2eaee03 100644 (file)
@@ -224,8 +224,7 @@ struct usb_serial_driver {
        /* Called by console with tty = NULL and by tty */
        int  (*open)(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
-       void (*close)(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp);
+       void (*close)(struct usb_serial_port *port);
        int  (*write)(struct tty_struct *tty, struct usb_serial_port *port,
                        const unsigned char *buf, int count);
        /* Called only by the tty layer */
@@ -241,6 +240,10 @@ struct usb_serial_driver {
        int  (*tiocmget)(struct tty_struct *tty, struct file *file);
        int  (*tiocmset)(struct tty_struct *tty, struct file *file,
                         unsigned int set, unsigned int clear);
+       /* Called by the tty layer for port level work. There may or may not
+          be an attached tty at this point */
+       void (*dtr_rts)(struct usb_serial_port *port, int on);
+       int  (*carrier_raised)(struct usb_serial_port *port);
        /* USB events */
        void (*read_int_callback)(struct urb *urb);
        void (*write_int_callback)(struct urb *urb);
@@ -283,8 +286,7 @@ extern int usb_serial_generic_open(struct tty_struct *tty,
                struct usb_serial_port *port, struct file *filp);
 extern int usb_serial_generic_write(struct tty_struct *tty,
        struct usb_serial_port *port, const unsigned char *buf, int count);
-extern void usb_serial_generic_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp);
+extern void usb_serial_generic_close(struct usb_serial_port *port);
 extern int usb_serial_generic_resume(struct usb_serial *serial);
 extern int usb_serial_generic_write_room(struct tty_struct *tty);
 extern int usb_serial_generic_chars_in_buffer(struct tty_struct *tty);
index 94c56d29869df77a2c72b7438762db7ff72fac9f..be7d255fc7cfbfc644fc5381fac0aaf9ee3e59e3 100644 (file)
 #define VIRTIO_BLK_F_GEOMETRY  4       /* Legacy geometry available  */
 #define VIRTIO_BLK_F_RO                5       /* Disk is read-only */
 #define VIRTIO_BLK_F_BLK_SIZE  6       /* Block size of disk is available*/
+#define VIRTIO_BLK_F_SCSI      7       /* Supports scsi command passthru */
+#define VIRTIO_BLK_F_IDENTIFY  8       /* ATA IDENTIFY supported */
+
+#define VIRTIO_BLK_ID_BYTES    (sizeof(__u16[256]))    /* IDENTIFY DATA */
 
 struct virtio_blk_config
 {
@@ -32,6 +36,7 @@ struct virtio_blk_config
        } geometry;
        /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
        __u32 blk_size;
+       __u8 identify[VIRTIO_BLK_ID_BYTES];
 } __attribute__((packed));
 
 /* These two define direction. */
@@ -55,6 +60,13 @@ struct virtio_blk_outhdr
        __u64 sector;
 };
 
+struct virtio_scsi_inhdr {
+       __u32 errors;
+       __u32 data_len;
+       __u32 sense_len;
+       __u32 residual;
+};
+
 /* And this is the final byte of the write scatter-gather list. */
 #define VIRTIO_BLK_S_OK                0
 #define VIRTIO_BLK_S_IOERR     1
index bc024632f365915f99894f5d799938f5e4e69b45..6788e1a4d4ca63e8cfc3b288f87d456334064c29 100644 (file)
@@ -132,8 +132,6 @@ static inline void __remove_wait_queue(wait_queue_head_t *head,
        list_del(&old->task_list);
 }
 
-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);
 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,
index 43b50d36925cab501acab17f7ed754867652aee5..3878d1dc7f596f8c7c4fb8d3fb547448a9b2dba1 100644 (file)
@@ -270,7 +270,7 @@ static inline unsigned char scsi_get_prot_type(struct scsi_cmnd *scmd)
 
 static inline sector_t scsi_get_lba(struct scsi_cmnd *scmd)
 {
-       return scmd->request->sector;
+       return blk_rq_pos(scmd->request);
 }
 
 static inline unsigned scsi_prot_sg_count(struct scsi_cmnd *cmd)
diff --git a/include/trace/block.h b/include/trace/block.h
deleted file mode 100644 (file)
index 25b7068..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef _TRACE_BLOCK_H
-#define _TRACE_BLOCK_H
-
-#include <linux/blkdev.h>
-#include <linux/tracepoint.h>
-
-DECLARE_TRACE(block_rq_abort,
-       TP_PROTO(struct request_queue *q, struct request *rq),
-             TP_ARGS(q, rq));
-
-DECLARE_TRACE(block_rq_insert,
-       TP_PROTO(struct request_queue *q, struct request *rq),
-             TP_ARGS(q, rq));
-
-DECLARE_TRACE(block_rq_issue,
-       TP_PROTO(struct request_queue *q, struct request *rq),
-             TP_ARGS(q, rq));
-
-DECLARE_TRACE(block_rq_requeue,
-       TP_PROTO(struct request_queue *q, struct request *rq),
-             TP_ARGS(q, rq));
-
-DECLARE_TRACE(block_rq_complete,
-       TP_PROTO(struct request_queue *q, struct request *rq),
-             TP_ARGS(q, rq));
-
-DECLARE_TRACE(block_bio_bounce,
-       TP_PROTO(struct request_queue *q, struct bio *bio),
-             TP_ARGS(q, bio));
-
-DECLARE_TRACE(block_bio_complete,
-       TP_PROTO(struct request_queue *q, struct bio *bio),
-             TP_ARGS(q, bio));
-
-DECLARE_TRACE(block_bio_backmerge,
-       TP_PROTO(struct request_queue *q, struct bio *bio),
-             TP_ARGS(q, bio));
-
-DECLARE_TRACE(block_bio_frontmerge,
-       TP_PROTO(struct request_queue *q, struct bio *bio),
-             TP_ARGS(q, bio));
-
-DECLARE_TRACE(block_bio_queue,
-       TP_PROTO(struct request_queue *q, struct bio *bio),
-             TP_ARGS(q, bio));
-
-DECLARE_TRACE(block_getrq,
-       TP_PROTO(struct request_queue *q, struct bio *bio, int rw),
-             TP_ARGS(q, bio, rw));
-
-DECLARE_TRACE(block_sleeprq,
-       TP_PROTO(struct request_queue *q, struct bio *bio, int rw),
-             TP_ARGS(q, bio, rw));
-
-DECLARE_TRACE(block_plug,
-       TP_PROTO(struct request_queue *q),
-             TP_ARGS(q));
-
-DECLARE_TRACE(block_unplug_timer,
-       TP_PROTO(struct request_queue *q),
-             TP_ARGS(q));
-
-DECLARE_TRACE(block_unplug_io,
-       TP_PROTO(struct request_queue *q),
-             TP_ARGS(q));
-
-DECLARE_TRACE(block_split,
-       TP_PROTO(struct request_queue *q, struct bio *bio, unsigned int pdu),
-             TP_ARGS(q, bio, pdu));
-
-DECLARE_TRACE(block_remap,
-       TP_PROTO(struct request_queue *q, struct bio *bio, dev_t dev,
-                sector_t from, sector_t to),
-             TP_ARGS(q, bio, dev, from, to));
-
-#endif
diff --git a/include/trace/define_trace.h b/include/trace/define_trace.h
new file mode 100644 (file)
index 0000000..f7a7ae1
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Trace files that want to automate creationg of all tracepoints defined
+ * in their file should include this file. The following are macros that the
+ * trace file may define:
+ *
+ * TRACE_SYSTEM defines the system the tracepoint is for
+ *
+ * TRACE_INCLUDE_FILE if the file name is something other than TRACE_SYSTEM.h
+ *     This macro may be defined to tell define_trace.h what file to include.
+ *     Note, leave off the ".h".
+ *
+ * TRACE_INCLUDE_PATH if the path is something other than core kernel include/trace
+ *     then this macro can define the path to use. Note, the path is relative to
+ *     define_trace.h, not the file including it. Full path names for out of tree
+ *     modules must be used.
+ */
+
+#ifdef CREATE_TRACE_POINTS
+
+/* Prevent recursion */
+#undef CREATE_TRACE_POINTS
+
+#include <linux/stringify.h>
+
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, args, tstruct, assign, print) \
+       DEFINE_TRACE(name)
+
+#undef DECLARE_TRACE
+#define DECLARE_TRACE(name, proto, args)       \
+       DEFINE_TRACE(name)
+
+#undef TRACE_INCLUDE
+#undef __TRACE_INCLUDE
+
+#ifndef TRACE_INCLUDE_FILE
+# define TRACE_INCLUDE_FILE TRACE_SYSTEM
+# define UNDEF_TRACE_INCLUDE_FILE
+#endif
+
+#ifndef TRACE_INCLUDE_PATH
+# define __TRACE_INCLUDE(system) <trace/events/system.h>
+# define UNDEF_TRACE_INCLUDE_PATH
+#else
+# define __TRACE_INCLUDE(system) __stringify(TRACE_INCLUDE_PATH/system.h)
+#endif
+
+# define TRACE_INCLUDE(system) __TRACE_INCLUDE(system)
+
+/* Let the trace headers be reread */
+#define TRACE_HEADER_MULTI_READ
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+#ifdef CONFIG_EVENT_TRACING
+#include <trace/ftrace.h>
+#endif
+
+#undef TRACE_HEADER_MULTI_READ
+
+/* Only undef what we defined in this file */
+#ifdef UNDEF_TRACE_INCLUDE_FILE
+# undef TRACE_INCLUDE_FILE
+# undef UNDEF_TRACE_INCLUDE_FILE
+#endif
+
+#ifdef UNDEF_TRACE_INCLUDE_PATH
+# undef TRACE_INCLUDE_PATH
+# undef UNDEF_TRACE_INCLUDE_PATH
+#endif
+
+/* We may be processing more files */
+#define CREATE_TRACE_POINTS
+
+#endif /* CREATE_TRACE_POINTS */
diff --git a/include/trace/events/block.h b/include/trace/events/block.h
new file mode 100644 (file)
index 0000000..d6b05f4
--- /dev/null
@@ -0,0 +1,493 @@
+#if !defined(_TRACE_BLOCK_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_BLOCK_H
+
+#include <linux/blktrace_api.h>
+#include <linux/blkdev.h>
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM block
+
+TRACE_EVENT(block_rq_abort,
+
+       TP_PROTO(struct request_queue *q, struct request *rq),
+
+       TP_ARGS(q, rq),
+
+       TP_STRUCT__entry(
+               __field(  dev_t,        dev                     )
+               __field(  sector_t,     sector                  )
+               __field(  unsigned int, nr_sector               )
+               __field(  int,          errors                  )
+               __array(  char,         rwbs,   6               )
+               __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
+       ),
+
+       TP_fast_assign(
+               __entry->dev       = rq->rq_disk ? disk_devt(rq->rq_disk) : 0;
+               __entry->sector    = blk_pc_request(rq) ? 0 : blk_rq_pos(rq);
+               __entry->nr_sector = blk_pc_request(rq) ? 0 : blk_rq_sectors(rq);
+               __entry->errors    = rq->errors;
+
+               blk_fill_rwbs_rq(__entry->rwbs, rq);
+               blk_dump_cmd(__get_str(cmd), rq);
+       ),
+
+       TP_printk("%d,%d %s (%s) %llu + %u [%d]",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->rwbs, __get_str(cmd),
+                 (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->errors)
+);
+
+TRACE_EVENT(block_rq_insert,
+
+       TP_PROTO(struct request_queue *q, struct request *rq),
+
+       TP_ARGS(q, rq),
+
+       TP_STRUCT__entry(
+               __field(  dev_t,        dev                     )
+               __field(  sector_t,     sector                  )
+               __field(  unsigned int, nr_sector               )
+               __field(  unsigned int, bytes                   )
+               __array(  char,         rwbs,   6               )
+               __array(  char,         comm,   TASK_COMM_LEN   )
+               __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
+       ),
+
+       TP_fast_assign(
+               __entry->dev       = rq->rq_disk ? disk_devt(rq->rq_disk) : 0;
+               __entry->sector    = blk_pc_request(rq) ? 0 : blk_rq_pos(rq);
+               __entry->nr_sector = blk_pc_request(rq) ? 0 : blk_rq_sectors(rq);
+               __entry->bytes     = blk_pc_request(rq) ? blk_rq_bytes(rq) : 0;
+
+               blk_fill_rwbs_rq(__entry->rwbs, rq);
+               blk_dump_cmd(__get_str(cmd), rq);
+               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+       ),
+
+       TP_printk("%d,%d %s %u (%s) %llu + %u [%s]",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->rwbs, __entry->bytes, __get_str(cmd),
+                 (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->comm)
+);
+
+TRACE_EVENT(block_rq_issue,
+
+       TP_PROTO(struct request_queue *q, struct request *rq),
+
+       TP_ARGS(q, rq),
+
+       TP_STRUCT__entry(
+               __field(  dev_t,        dev                     )
+               __field(  sector_t,     sector                  )
+               __field(  unsigned int, nr_sector               )
+               __field(  unsigned int, bytes                   )
+               __array(  char,         rwbs,   6               )
+               __array(  char,         comm,   TASK_COMM_LEN   )
+               __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
+       ),
+
+       TP_fast_assign(
+               __entry->dev       = rq->rq_disk ? disk_devt(rq->rq_disk) : 0;
+               __entry->sector    = blk_pc_request(rq) ? 0 : blk_rq_pos(rq);
+               __entry->nr_sector = blk_pc_request(rq) ? 0 : blk_rq_sectors(rq);
+               __entry->bytes     = blk_pc_request(rq) ? blk_rq_bytes(rq) : 0;
+
+               blk_fill_rwbs_rq(__entry->rwbs, rq);
+               blk_dump_cmd(__get_str(cmd), rq);
+               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+       ),
+
+       TP_printk("%d,%d %s %u (%s) %llu + %u [%s]",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->rwbs, __entry->bytes, __get_str(cmd),
+                 (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->comm)
+);
+
+TRACE_EVENT(block_rq_requeue,
+
+       TP_PROTO(struct request_queue *q, struct request *rq),
+
+       TP_ARGS(q, rq),
+
+       TP_STRUCT__entry(
+               __field(  dev_t,        dev                     )
+               __field(  sector_t,     sector                  )
+               __field(  unsigned int, nr_sector               )
+               __field(  int,          errors                  )
+               __array(  char,         rwbs,   6               )
+               __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
+       ),
+
+       TP_fast_assign(
+               __entry->dev       = rq->rq_disk ? disk_devt(rq->rq_disk) : 0;
+               __entry->sector    = blk_pc_request(rq) ? 0 : blk_rq_pos(rq);
+               __entry->nr_sector = blk_pc_request(rq) ? 0 : blk_rq_sectors(rq);
+               __entry->errors    = rq->errors;
+
+               blk_fill_rwbs_rq(__entry->rwbs, rq);
+               blk_dump_cmd(__get_str(cmd), rq);
+       ),
+
+       TP_printk("%d,%d %s (%s) %llu + %u [%d]",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->rwbs, __get_str(cmd),
+                 (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->errors)
+);
+
+TRACE_EVENT(block_rq_complete,
+
+       TP_PROTO(struct request_queue *q, struct request *rq),
+
+       TP_ARGS(q, rq),
+
+       TP_STRUCT__entry(
+               __field(  dev_t,        dev                     )
+               __field(  sector_t,     sector                  )
+               __field(  unsigned int, nr_sector               )
+               __field(  int,          errors                  )
+               __array(  char,         rwbs,   6               )
+               __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
+       ),
+
+       TP_fast_assign(
+               __entry->dev       = rq->rq_disk ? disk_devt(rq->rq_disk) : 0;
+               __entry->sector    = blk_pc_request(rq) ? 0 : blk_rq_pos(rq);
+               __entry->nr_sector = blk_pc_request(rq) ? 0 : blk_rq_sectors(rq);
+               __entry->errors    = rq->errors;
+
+               blk_fill_rwbs_rq(__entry->rwbs, rq);
+               blk_dump_cmd(__get_str(cmd), rq);
+       ),
+
+       TP_printk("%d,%d %s (%s) %llu + %u [%d]",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->rwbs, __get_str(cmd),
+                 (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->errors)
+);
+TRACE_EVENT(block_bio_bounce,
+
+       TP_PROTO(struct request_queue *q, struct bio *bio),
+
+       TP_ARGS(q, bio),
+
+       TP_STRUCT__entry(
+               __field( dev_t,         dev                     )
+               __field( sector_t,      sector                  )
+               __field( unsigned int,  nr_sector               )
+               __array( char,          rwbs,   6               )
+               __array( char,          comm,   TASK_COMM_LEN   )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = bio->bi_bdev->bd_dev;
+               __entry->sector         = bio->bi_sector;
+               __entry->nr_sector      = bio->bi_size >> 9;
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+       ),
+
+       TP_printk("%d,%d %s %llu + %u [%s]",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
+                 (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->comm)
+);
+
+TRACE_EVENT(block_bio_complete,
+
+       TP_PROTO(struct request_queue *q, struct bio *bio),
+
+       TP_ARGS(q, bio),
+
+       TP_STRUCT__entry(
+               __field( dev_t,         dev             )
+               __field( sector_t,      sector          )
+               __field( unsigned,      nr_sector       )
+               __field( int,           error           )
+               __array( char,          rwbs,   6       )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = bio->bi_bdev->bd_dev;
+               __entry->sector         = bio->bi_sector;
+               __entry->nr_sector      = bio->bi_size >> 9;
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+       ),
+
+       TP_printk("%d,%d %s %llu + %u [%d]",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
+                 (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->error)
+);
+
+TRACE_EVENT(block_bio_backmerge,
+
+       TP_PROTO(struct request_queue *q, struct bio *bio),
+
+       TP_ARGS(q, bio),
+
+       TP_STRUCT__entry(
+               __field( dev_t,         dev                     )
+               __field( sector_t,      sector                  )
+               __field( unsigned int,  nr_sector               )
+               __array( char,          rwbs,   6               )
+               __array( char,          comm,   TASK_COMM_LEN   )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = bio->bi_bdev->bd_dev;
+               __entry->sector         = bio->bi_sector;
+               __entry->nr_sector      = bio->bi_size >> 9;
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+       ),
+
+       TP_printk("%d,%d %s %llu + %u [%s]",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
+                 (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->comm)
+);
+
+TRACE_EVENT(block_bio_frontmerge,
+
+       TP_PROTO(struct request_queue *q, struct bio *bio),
+
+       TP_ARGS(q, bio),
+
+       TP_STRUCT__entry(
+               __field( dev_t,         dev                     )
+               __field( sector_t,      sector                  )
+               __field( unsigned,      nr_sector               )
+               __array( char,          rwbs,   6               )
+               __array( char,          comm,   TASK_COMM_LEN   )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = bio->bi_bdev->bd_dev;
+               __entry->sector         = bio->bi_sector;
+               __entry->nr_sector      = bio->bi_size >> 9;
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+       ),
+
+       TP_printk("%d,%d %s %llu + %u [%s]",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
+                 (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->comm)
+);
+
+TRACE_EVENT(block_bio_queue,
+
+       TP_PROTO(struct request_queue *q, struct bio *bio),
+
+       TP_ARGS(q, bio),
+
+       TP_STRUCT__entry(
+               __field( dev_t,         dev                     )
+               __field( sector_t,      sector                  )
+               __field( unsigned int,  nr_sector               )
+               __array( char,          rwbs,   6               )
+               __array( char,          comm,   TASK_COMM_LEN   )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = bio->bi_bdev->bd_dev;
+               __entry->sector         = bio->bi_sector;
+               __entry->nr_sector      = bio->bi_size >> 9;
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+       ),
+
+       TP_printk("%d,%d %s %llu + %u [%s]",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
+                 (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->comm)
+);
+
+TRACE_EVENT(block_getrq,
+
+       TP_PROTO(struct request_queue *q, struct bio *bio, int rw),
+
+       TP_ARGS(q, bio, rw),
+
+       TP_STRUCT__entry(
+               __field( dev_t,         dev                     )
+               __field( sector_t,      sector                  )
+               __field( unsigned int,  nr_sector               )
+               __array( char,          rwbs,   6               )
+               __array( char,          comm,   TASK_COMM_LEN   )
+        ),
+
+       TP_fast_assign(
+               __entry->dev            = bio ? bio->bi_bdev->bd_dev : 0;
+               __entry->sector         = bio ? bio->bi_sector : 0;
+               __entry->nr_sector      = bio ? bio->bi_size >> 9 : 0;
+               blk_fill_rwbs(__entry->rwbs,
+                             bio ? bio->bi_rw : 0, __entry->nr_sector);
+               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+        ),
+
+       TP_printk("%d,%d %s %llu + %u [%s]",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
+                 (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->comm)
+);
+
+TRACE_EVENT(block_sleeprq,
+
+       TP_PROTO(struct request_queue *q, struct bio *bio, int rw),
+
+       TP_ARGS(q, bio, rw),
+
+       TP_STRUCT__entry(
+               __field( dev_t,         dev                     )
+               __field( sector_t,      sector                  )
+               __field( unsigned int,  nr_sector               )
+               __array( char,          rwbs,   6               )
+               __array( char,          comm,   TASK_COMM_LEN   )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = bio ? bio->bi_bdev->bd_dev : 0;
+               __entry->sector         = bio ? bio->bi_sector : 0;
+               __entry->nr_sector      = bio ? bio->bi_size >> 9 : 0;
+               blk_fill_rwbs(__entry->rwbs,
+                           bio ? bio->bi_rw : 0, __entry->nr_sector);
+               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+       ),
+
+       TP_printk("%d,%d %s %llu + %u [%s]",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
+                 (unsigned long long)__entry->sector,
+                 __entry->nr_sector, __entry->comm)
+);
+
+TRACE_EVENT(block_plug,
+
+       TP_PROTO(struct request_queue *q),
+
+       TP_ARGS(q),
+
+       TP_STRUCT__entry(
+               __array( char,          comm,   TASK_COMM_LEN   )
+       ),
+
+       TP_fast_assign(
+               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+       ),
+
+       TP_printk("[%s]", __entry->comm)
+);
+
+TRACE_EVENT(block_unplug_timer,
+
+       TP_PROTO(struct request_queue *q),
+
+       TP_ARGS(q),
+
+       TP_STRUCT__entry(
+               __field( int,           nr_rq                   )
+               __array( char,          comm,   TASK_COMM_LEN   )
+       ),
+
+       TP_fast_assign(
+               __entry->nr_rq  = q->rq.count[READ] + q->rq.count[WRITE];
+               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+       ),
+
+       TP_printk("[%s] %d", __entry->comm, __entry->nr_rq)
+);
+
+TRACE_EVENT(block_unplug_io,
+
+       TP_PROTO(struct request_queue *q),
+
+       TP_ARGS(q),
+
+       TP_STRUCT__entry(
+               __field( int,           nr_rq                   )
+               __array( char,          comm,   TASK_COMM_LEN   )
+       ),
+
+       TP_fast_assign(
+               __entry->nr_rq  = q->rq.count[READ] + q->rq.count[WRITE];
+               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+       ),
+
+       TP_printk("[%s] %d", __entry->comm, __entry->nr_rq)
+);
+
+TRACE_EVENT(block_split,
+
+       TP_PROTO(struct request_queue *q, struct bio *bio,
+                unsigned int new_sector),
+
+       TP_ARGS(q, bio, new_sector),
+
+       TP_STRUCT__entry(
+               __field( dev_t,         dev                             )
+               __field( sector_t,      sector                          )
+               __field( sector_t,      new_sector                      )
+               __array( char,          rwbs,           6               )
+               __array( char,          comm,           TASK_COMM_LEN   )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = bio->bi_bdev->bd_dev;
+               __entry->sector         = bio->bi_sector;
+               __entry->new_sector     = new_sector;
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+       ),
+
+       TP_printk("%d,%d %s %llu / %llu [%s]",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
+                 (unsigned long long)__entry->sector,
+                 (unsigned long long)__entry->new_sector,
+                 __entry->comm)
+);
+
+TRACE_EVENT(block_remap,
+
+       TP_PROTO(struct request_queue *q, struct bio *bio, dev_t dev,
+                sector_t from),
+
+       TP_ARGS(q, bio, dev, from),
+
+       TP_STRUCT__entry(
+               __field( dev_t,         dev             )
+               __field( sector_t,      sector          )
+               __field( unsigned int,  nr_sector       )
+               __field( dev_t,         old_dev         )
+               __field( sector_t,      old_sector      )
+               __array( char,          rwbs,   6       )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = bio->bi_bdev->bd_dev;
+               __entry->sector         = bio->bi_sector;
+               __entry->nr_sector      = bio->bi_size >> 9;
+               __entry->old_dev        = dev;
+               __entry->old_sector     = from;
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+       ),
+
+       TP_printk("%d,%d %s %llu + %u <- (%d,%d) %llu",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
+                 (unsigned long long)__entry->sector,
+                 __entry->nr_sector,
+                 MAJOR(__entry->old_dev), MINOR(__entry->old_dev),
+                 (unsigned long long)__entry->old_sector)
+);
+
+#endif /* _TRACE_BLOCK_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
+
diff --git a/include/trace/events/irq.h b/include/trace/events/irq.h
new file mode 100644 (file)
index 0000000..b0c7ede
--- /dev/null
@@ -0,0 +1,145 @@
+#if !defined(_TRACE_IRQ_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_IRQ_H
+
+#include <linux/tracepoint.h>
+#include <linux/interrupt.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM irq
+
+#define softirq_name(sirq) { sirq##_SOFTIRQ, #sirq }
+#define show_softirq_name(val)                 \
+       __print_symbolic(val,                   \
+                        softirq_name(HI),      \
+                        softirq_name(TIMER),   \
+                        softirq_name(NET_TX),  \
+                        softirq_name(NET_RX),  \
+                        softirq_name(BLOCK),   \
+                        softirq_name(TASKLET), \
+                        softirq_name(SCHED),   \
+                        softirq_name(HRTIMER), \
+                        softirq_name(RCU))
+
+/**
+ * irq_handler_entry - called immediately before the irq action handler
+ * @irq: irq number
+ * @action: pointer to struct irqaction
+ *
+ * The struct irqaction pointed to by @action contains various
+ * information about the handler, including the device name,
+ * @action->name, and the device id, @action->dev_id. When used in
+ * conjunction with the irq_handler_exit tracepoint, we can figure
+ * out irq handler latencies.
+ */
+TRACE_EVENT(irq_handler_entry,
+
+       TP_PROTO(int irq, struct irqaction *action),
+
+       TP_ARGS(irq, action),
+
+       TP_STRUCT__entry(
+               __field(        int,    irq             )
+               __string(       name,   action->name    )
+       ),
+
+       TP_fast_assign(
+               __entry->irq = irq;
+               __assign_str(name, action->name);
+       ),
+
+       TP_printk("irq=%d handler=%s", __entry->irq, __get_str(name))
+);
+
+/**
+ * irq_handler_exit - called immediately after the irq action handler returns
+ * @irq: irq number
+ * @action: pointer to struct irqaction
+ * @ret: return value
+ *
+ * If the @ret value is set to IRQ_HANDLED, then we know that the corresponding
+ * @action->handler scuccessully handled this irq. Otherwise, the irq might be
+ * a shared irq line, or the irq was not handled successfully. Can be used in
+ * conjunction with the irq_handler_entry to understand irq handler latencies.
+ */
+TRACE_EVENT(irq_handler_exit,
+
+       TP_PROTO(int irq, struct irqaction *action, int ret),
+
+       TP_ARGS(irq, action, ret),
+
+       TP_STRUCT__entry(
+               __field(        int,    irq     )
+               __field(        int,    ret     )
+       ),
+
+       TP_fast_assign(
+               __entry->irq    = irq;
+               __entry->ret    = ret;
+       ),
+
+       TP_printk("irq=%d return=%s",
+                 __entry->irq, __entry->ret ? "handled" : "unhandled")
+);
+
+/**
+ * softirq_entry - called immediately before the softirq handler
+ * @h: pointer to struct softirq_action
+ * @vec: pointer to first struct softirq_action in softirq_vec array
+ *
+ * The @h parameter, contains a pointer to the struct softirq_action
+ * which has a pointer to the action handler that is called. By subtracting
+ * the @vec pointer from the @h pointer, we can determine the softirq
+ * number. Also, when used in combination with the softirq_exit tracepoint
+ * we can determine the softirq latency.
+ */
+TRACE_EVENT(softirq_entry,
+
+       TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
+
+       TP_ARGS(h, vec),
+
+       TP_STRUCT__entry(
+               __field(        int,    vec                     )
+       ),
+
+       TP_fast_assign(
+               __entry->vec = (int)(h - vec);
+       ),
+
+       TP_printk("softirq=%d action=%s", __entry->vec,
+                 show_softirq_name(__entry->vec))
+);
+
+/**
+ * softirq_exit - called immediately after the softirq handler returns
+ * @h: pointer to struct softirq_action
+ * @vec: pointer to first struct softirq_action in softirq_vec array
+ *
+ * The @h parameter contains a pointer to the struct softirq_action
+ * that has handled the softirq. By subtracting the @vec pointer from
+ * the @h pointer, we can determine the softirq number. Also, when used in
+ * combination with the softirq_entry tracepoint we can determine the softirq
+ * latency.
+ */
+TRACE_EVENT(softirq_exit,
+
+       TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
+
+       TP_ARGS(h, vec),
+
+       TP_STRUCT__entry(
+               __field(        int,    vec                     )
+       ),
+
+       TP_fast_assign(
+               __entry->vec = (int)(h - vec);
+       ),
+
+       TP_printk("softirq=%d action=%s", __entry->vec,
+                 show_softirq_name(__entry->vec))
+);
+
+#endif /*  _TRACE_IRQ_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h
new file mode 100644 (file)
index 0000000..9baba50
--- /dev/null
@@ -0,0 +1,231 @@
+#if !defined(_TRACE_KMEM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_KMEM_H
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kmem
+
+/*
+ * The order of these masks is important. Matching masks will be seen
+ * first and the left over flags will end up showing by themselves.
+ *
+ * For example, if we have GFP_KERNEL before GFP_USER we wil get:
+ *
+ *  GFP_KERNEL|GFP_HARDWALL
+ *
+ * Thus most bits set go first.
+ */
+#define show_gfp_flags(flags)                                          \
+       (flags) ? __print_flags(flags, "|",                             \
+       {(unsigned long)GFP_HIGHUSER_MOVABLE,   "GFP_HIGHUSER_MOVABLE"}, \
+       {(unsigned long)GFP_HIGHUSER,           "GFP_HIGHUSER"},        \
+       {(unsigned long)GFP_USER,               "GFP_USER"},            \
+       {(unsigned long)GFP_TEMPORARY,          "GFP_TEMPORARY"},       \
+       {(unsigned long)GFP_KERNEL,             "GFP_KERNEL"},          \
+       {(unsigned long)GFP_NOFS,               "GFP_NOFS"},            \
+       {(unsigned long)GFP_ATOMIC,             "GFP_ATOMIC"},          \
+       {(unsigned long)GFP_NOIO,               "GFP_NOIO"},            \
+       {(unsigned long)__GFP_HIGH,             "GFP_HIGH"},            \
+       {(unsigned long)__GFP_WAIT,             "GFP_WAIT"},            \
+       {(unsigned long)__GFP_IO,               "GFP_IO"},              \
+       {(unsigned long)__GFP_COLD,             "GFP_COLD"},            \
+       {(unsigned long)__GFP_NOWARN,           "GFP_NOWARN"},          \
+       {(unsigned long)__GFP_REPEAT,           "GFP_REPEAT"},          \
+       {(unsigned long)__GFP_NOFAIL,           "GFP_NOFAIL"},          \
+       {(unsigned long)__GFP_NORETRY,          "GFP_NORETRY"},         \
+       {(unsigned long)__GFP_COMP,             "GFP_COMP"},            \
+       {(unsigned long)__GFP_ZERO,             "GFP_ZERO"},            \
+       {(unsigned long)__GFP_NOMEMALLOC,       "GFP_NOMEMALLOC"},      \
+       {(unsigned long)__GFP_HARDWALL,         "GFP_HARDWALL"},        \
+       {(unsigned long)__GFP_THISNODE,         "GFP_THISNODE"},        \
+       {(unsigned long)__GFP_RECLAIMABLE,      "GFP_RECLAIMABLE"},     \
+       {(unsigned long)__GFP_MOVABLE,          "GFP_MOVABLE"}          \
+       ) : "GFP_NOWAIT"
+
+TRACE_EVENT(kmalloc,
+
+       TP_PROTO(unsigned long call_site,
+                const void *ptr,
+                size_t bytes_req,
+                size_t bytes_alloc,
+                gfp_t gfp_flags),
+
+       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags),
+
+       TP_STRUCT__entry(
+               __field(        unsigned long,  call_site       )
+               __field(        const void *,   ptr             )
+               __field(        size_t,         bytes_req       )
+               __field(        size_t,         bytes_alloc     )
+               __field(        gfp_t,          gfp_flags       )
+       ),
+
+       TP_fast_assign(
+               __entry->call_site      = call_site;
+               __entry->ptr            = ptr;
+               __entry->bytes_req      = bytes_req;
+               __entry->bytes_alloc    = bytes_alloc;
+               __entry->gfp_flags      = gfp_flags;
+       ),
+
+       TP_printk("call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s",
+               __entry->call_site,
+               __entry->ptr,
+               __entry->bytes_req,
+               __entry->bytes_alloc,
+               show_gfp_flags(__entry->gfp_flags))
+);
+
+TRACE_EVENT(kmem_cache_alloc,
+
+       TP_PROTO(unsigned long call_site,
+                const void *ptr,
+                size_t bytes_req,
+                size_t bytes_alloc,
+                gfp_t gfp_flags),
+
+       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags),
+
+       TP_STRUCT__entry(
+               __field(        unsigned long,  call_site       )
+               __field(        const void *,   ptr             )
+               __field(        size_t,         bytes_req       )
+               __field(        size_t,         bytes_alloc     )
+               __field(        gfp_t,          gfp_flags       )
+       ),
+
+       TP_fast_assign(
+               __entry->call_site      = call_site;
+               __entry->ptr            = ptr;
+               __entry->bytes_req      = bytes_req;
+               __entry->bytes_alloc    = bytes_alloc;
+               __entry->gfp_flags      = gfp_flags;
+       ),
+
+       TP_printk("call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s",
+               __entry->call_site,
+               __entry->ptr,
+               __entry->bytes_req,
+               __entry->bytes_alloc,
+               show_gfp_flags(__entry->gfp_flags))
+);
+
+TRACE_EVENT(kmalloc_node,
+
+       TP_PROTO(unsigned long call_site,
+                const void *ptr,
+                size_t bytes_req,
+                size_t bytes_alloc,
+                gfp_t gfp_flags,
+                int node),
+
+       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags, node),
+
+       TP_STRUCT__entry(
+               __field(        unsigned long,  call_site       )
+               __field(        const void *,   ptr             )
+               __field(        size_t,         bytes_req       )
+               __field(        size_t,         bytes_alloc     )
+               __field(        gfp_t,          gfp_flags       )
+               __field(        int,            node            )
+       ),
+
+       TP_fast_assign(
+               __entry->call_site      = call_site;
+               __entry->ptr            = ptr;
+               __entry->bytes_req      = bytes_req;
+               __entry->bytes_alloc    = bytes_alloc;
+               __entry->gfp_flags      = gfp_flags;
+               __entry->node           = node;
+       ),
+
+       TP_printk("call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s node=%d",
+               __entry->call_site,
+               __entry->ptr,
+               __entry->bytes_req,
+               __entry->bytes_alloc,
+               show_gfp_flags(__entry->gfp_flags),
+               __entry->node)
+);
+
+TRACE_EVENT(kmem_cache_alloc_node,
+
+       TP_PROTO(unsigned long call_site,
+                const void *ptr,
+                size_t bytes_req,
+                size_t bytes_alloc,
+                gfp_t gfp_flags,
+                int node),
+
+       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags, node),
+
+       TP_STRUCT__entry(
+               __field(        unsigned long,  call_site       )
+               __field(        const void *,   ptr             )
+               __field(        size_t,         bytes_req       )
+               __field(        size_t,         bytes_alloc     )
+               __field(        gfp_t,          gfp_flags       )
+               __field(        int,            node            )
+       ),
+
+       TP_fast_assign(
+               __entry->call_site      = call_site;
+               __entry->ptr            = ptr;
+               __entry->bytes_req      = bytes_req;
+               __entry->bytes_alloc    = bytes_alloc;
+               __entry->gfp_flags      = gfp_flags;
+               __entry->node           = node;
+       ),
+
+       TP_printk("call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s node=%d",
+               __entry->call_site,
+               __entry->ptr,
+               __entry->bytes_req,
+               __entry->bytes_alloc,
+               show_gfp_flags(__entry->gfp_flags),
+               __entry->node)
+);
+
+TRACE_EVENT(kfree,
+
+       TP_PROTO(unsigned long call_site, const void *ptr),
+
+       TP_ARGS(call_site, ptr),
+
+       TP_STRUCT__entry(
+               __field(        unsigned long,  call_site       )
+               __field(        const void *,   ptr             )
+       ),
+
+       TP_fast_assign(
+               __entry->call_site      = call_site;
+               __entry->ptr            = ptr;
+       ),
+
+       TP_printk("call_site=%lx ptr=%p", __entry->call_site, __entry->ptr)
+);
+
+TRACE_EVENT(kmem_cache_free,
+
+       TP_PROTO(unsigned long call_site, const void *ptr),
+
+       TP_ARGS(call_site, ptr),
+
+       TP_STRUCT__entry(
+               __field(        unsigned long,  call_site       )
+               __field(        const void *,   ptr             )
+       ),
+
+       TP_fast_assign(
+               __entry->call_site      = call_site;
+               __entry->ptr            = ptr;
+       ),
+
+       TP_printk("call_site=%lx ptr=%p", __entry->call_site, __entry->ptr)
+);
+#endif /* _TRACE_KMEM_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/lockdep.h b/include/trace/events/lockdep.h
new file mode 100644 (file)
index 0000000..0e956c9
--- /dev/null
@@ -0,0 +1,96 @@
+#if !defined(_TRACE_LOCKDEP_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_LOCKDEP_H
+
+#include <linux/lockdep.h>
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM lockdep
+
+#ifdef CONFIG_LOCKDEP
+
+TRACE_EVENT(lock_acquire,
+
+       TP_PROTO(struct lockdep_map *lock, unsigned int subclass,
+               int trylock, int read, int check,
+               struct lockdep_map *next_lock, unsigned long ip),
+
+       TP_ARGS(lock, subclass, trylock, read, check, next_lock, ip),
+
+       TP_STRUCT__entry(
+               __field(unsigned int, flags)
+               __string(name, lock->name)
+       ),
+
+       TP_fast_assign(
+               __entry->flags = (trylock ? 1 : 0) | (read ? 2 : 0);
+               __assign_str(name, lock->name);
+       ),
+
+       TP_printk("%s%s%s", (__entry->flags & 1) ? "try " : "",
+                 (__entry->flags & 2) ? "read " : "",
+                 __get_str(name))
+);
+
+TRACE_EVENT(lock_release,
+
+       TP_PROTO(struct lockdep_map *lock, int nested, unsigned long ip),
+
+       TP_ARGS(lock, nested, ip),
+
+       TP_STRUCT__entry(
+               __string(name, lock->name)
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, lock->name);
+       ),
+
+       TP_printk("%s", __get_str(name))
+);
+
+#ifdef CONFIG_LOCK_STAT
+
+TRACE_EVENT(lock_contended,
+
+       TP_PROTO(struct lockdep_map *lock, unsigned long ip),
+
+       TP_ARGS(lock, ip),
+
+       TP_STRUCT__entry(
+               __string(name, lock->name)
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, lock->name);
+       ),
+
+       TP_printk("%s", __get_str(name))
+);
+
+TRACE_EVENT(lock_acquired,
+       TP_PROTO(struct lockdep_map *lock, unsigned long ip, s64 waittime),
+
+       TP_ARGS(lock, ip, waittime),
+
+       TP_STRUCT__entry(
+               __string(name, lock->name)
+               __field(unsigned long, wait_usec)
+               __field(unsigned long, wait_nsec_rem)
+       ),
+       TP_fast_assign(
+               __assign_str(name, lock->name);
+               __entry->wait_nsec_rem = do_div(waittime, NSEC_PER_USEC);
+               __entry->wait_usec = (unsigned long) waittime;
+       ),
+       TP_printk("%s (%lu.%03lu us)", __get_str(name), __entry->wait_usec,
+                                      __entry->wait_nsec_rem)
+);
+
+#endif
+#endif
+
+#endif /* _TRACE_LOCKDEP_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
similarity index 91%
rename from include/trace/sched_event_types.h
rename to include/trace/events/sched.h
index 63547dc1125f7dc59bcc38cf55b92a253e178353..24ab5bcff7b2bfaebfe7ed4d544f286c43c416a3 100644 (file)
@@ -1,9 +1,8 @@
+#if !defined(_TRACE_SCHED_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SCHED_H
 
-/* use <trace/sched.h> instead */
-#ifndef TRACE_EVENT
-# error Do not include this file directly.
-# error Unless you know what you are doing.
-#endif
+#include <linux/sched.h>
+#include <linux/tracepoint.h>
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM sched
@@ -157,6 +156,7 @@ TRACE_EVENT(sched_switch,
                __array(        char,   prev_comm,      TASK_COMM_LEN   )
                __field(        pid_t,  prev_pid                        )
                __field(        int,    prev_prio                       )
+               __field(        long,   prev_state                      )
                __array(        char,   next_comm,      TASK_COMM_LEN   )
                __field(        pid_t,  next_pid                        )
                __field(        int,    next_prio                       )
@@ -166,13 +166,19 @@ TRACE_EVENT(sched_switch,
                memcpy(__entry->next_comm, next->comm, TASK_COMM_LEN);
                __entry->prev_pid       = prev->pid;
                __entry->prev_prio      = prev->prio;
+               __entry->prev_state     = prev->state;
                memcpy(__entry->prev_comm, prev->comm, TASK_COMM_LEN);
                __entry->next_pid       = next->pid;
                __entry->next_prio      = next->prio;
        ),
 
-       TP_printk("task %s:%d [%d] ==> %s:%d [%d]",
+       TP_printk("task %s:%d [%d] (%s) ==> %s:%d [%d]",
                __entry->prev_comm, __entry->prev_pid, __entry->prev_prio,
+               __entry->prev_state ?
+                 __print_flags(__entry->prev_state, "|",
+                               { 1, "S"} , { 2, "D" }, { 4, "T" }, { 8, "t" },
+                               { 16, "Z" }, { 32, "X" }, { 64, "x" },
+                               { 128, "W" }) : "R",
                __entry->next_comm, __entry->next_pid, __entry->next_prio)
 );
 
@@ -181,9 +187,9 @@ TRACE_EVENT(sched_switch,
  */
 TRACE_EVENT(sched_migrate_task,
 
-       TP_PROTO(struct task_struct *p, int orig_cpu, int dest_cpu),
+       TP_PROTO(struct task_struct *p, int dest_cpu),
 
-       TP_ARGS(p, orig_cpu, dest_cpu),
+       TP_ARGS(p, dest_cpu),
 
        TP_STRUCT__entry(
                __array(        char,   comm,   TASK_COMM_LEN   )
@@ -197,7 +203,7 @@ TRACE_EVENT(sched_migrate_task,
                memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
                __entry->pid            = p->pid;
                __entry->prio           = p->prio;
-               __entry->orig_cpu       = orig_cpu;
+               __entry->orig_cpu       = task_cpu(p);
                __entry->dest_cpu       = dest_cpu;
        ),
 
@@ -334,4 +340,7 @@ TRACE_EVENT(sched_signal_send,
                  __entry->sig, __entry->comm, __entry->pid)
 );
 
-#undef TRACE_SYSTEM
+#endif /* _TRACE_SCHED_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/skb.h b/include/trace/events/skb.h
new file mode 100644 (file)
index 0000000..1e8fabb
--- /dev/null
@@ -0,0 +1,40 @@
+#if !defined(_TRACE_SKB_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SKB_H
+
+#include <linux/skbuff.h>
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM skb
+
+/*
+ * Tracepoint for free an sk_buff:
+ */
+TRACE_EVENT(kfree_skb,
+
+       TP_PROTO(struct sk_buff *skb, void *location),
+
+       TP_ARGS(skb, location),
+
+       TP_STRUCT__entry(
+               __field(        void *,         skbaddr         )
+               __field(        unsigned short, protocol        )
+               __field(        void *,         location        )
+       ),
+
+       TP_fast_assign(
+               __entry->skbaddr = skb;
+               if (skb) {
+                       __entry->protocol = ntohs(skb->protocol);
+               }
+               __entry->location = location;
+       ),
+
+       TP_printk("skbaddr=%p protocol=%u location=%p",
+               __entry->skbaddr, __entry->protocol, __entry->location)
+);
+
+#endif /* _TRACE_SKB_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/workqueue.h b/include/trace/events/workqueue.h
new file mode 100644 (file)
index 0000000..035f1bf
--- /dev/null
@@ -0,0 +1,100 @@
+#if !defined(_TRACE_WORKQUEUE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_WORKQUEUE_H
+
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM workqueue
+
+TRACE_EVENT(workqueue_insertion,
+
+       TP_PROTO(struct task_struct *wq_thread, struct work_struct *work),
+
+       TP_ARGS(wq_thread, work),
+
+       TP_STRUCT__entry(
+               __array(char,           thread_comm,    TASK_COMM_LEN)
+               __field(pid_t,          thread_pid)
+               __field(work_func_t,    func)
+       ),
+
+       TP_fast_assign(
+               memcpy(__entry->thread_comm, wq_thread->comm, TASK_COMM_LEN);
+               __entry->thread_pid     = wq_thread->pid;
+               __entry->func           = work->func;
+       ),
+
+       TP_printk("thread=%s:%d func=%pF", __entry->thread_comm,
+               __entry->thread_pid, __entry->func)
+);
+
+TRACE_EVENT(workqueue_execution,
+
+       TP_PROTO(struct task_struct *wq_thread, struct work_struct *work),
+
+       TP_ARGS(wq_thread, work),
+
+       TP_STRUCT__entry(
+               __array(char,           thread_comm,    TASK_COMM_LEN)
+               __field(pid_t,          thread_pid)
+               __field(work_func_t,    func)
+       ),
+
+       TP_fast_assign(
+               memcpy(__entry->thread_comm, wq_thread->comm, TASK_COMM_LEN);
+               __entry->thread_pid     = wq_thread->pid;
+               __entry->func           = work->func;
+       ),
+
+       TP_printk("thread=%s:%d func=%pF", __entry->thread_comm,
+               __entry->thread_pid, __entry->func)
+);
+
+/* Trace the creation of one workqueue thread on a cpu */
+TRACE_EVENT(workqueue_creation,
+
+       TP_PROTO(struct task_struct *wq_thread, int cpu),
+
+       TP_ARGS(wq_thread, cpu),
+
+       TP_STRUCT__entry(
+               __array(char,   thread_comm,    TASK_COMM_LEN)
+               __field(pid_t,  thread_pid)
+               __field(int,    cpu)
+       ),
+
+       TP_fast_assign(
+               memcpy(__entry->thread_comm, wq_thread->comm, TASK_COMM_LEN);
+               __entry->thread_pid     = wq_thread->pid;
+               __entry->cpu            = cpu;
+       ),
+
+       TP_printk("thread=%s:%d cpu=%d", __entry->thread_comm,
+               __entry->thread_pid, __entry->cpu)
+);
+
+TRACE_EVENT(workqueue_destruction,
+
+       TP_PROTO(struct task_struct *wq_thread),
+
+       TP_ARGS(wq_thread),
+
+       TP_STRUCT__entry(
+               __array(char,   thread_comm,    TASK_COMM_LEN)
+               __field(pid_t,  thread_pid)
+       ),
+
+       TP_fast_assign(
+               memcpy(__entry->thread_comm, wq_thread->comm, TASK_COMM_LEN);
+               __entry->thread_pid     = wq_thread->pid;
+       ),
+
+       TP_printk("thread=%s:%d", __entry->thread_comm, __entry->thread_pid)
+);
+
+#endif /* _TRACE_WORKQUEUE_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
new file mode 100644 (file)
index 0000000..1867553
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * Stage 1 of the trace events.
+ *
+ * Override the macros in <trace/trace_events.h> to include the following:
+ *
+ * struct ftrace_raw_<call> {
+ *     struct trace_entry              ent;
+ *     <type>                          <item>;
+ *     <type2>                         <item2>[<len>];
+ *     [...]
+ * };
+ *
+ * The <type> <item> is created by the __field(type, item) macro or
+ * the __array(type2, item2, len) macro.
+ * We simply do "type item;", and that will create the fields
+ * in the structure.
+ */
+
+#include <linux/ftrace_event.h>
+
+#undef __field
+#define __field(type, item)            type    item;
+
+#undef __array
+#define __array(type, item, len)       type    item[len];
+
+#undef __dynamic_array
+#define __dynamic_array(type, item, len) unsigned short __data_loc_##item;
+
+#undef __string
+#define __string(item, src) __dynamic_array(char, item, -1)
+
+#undef TP_STRUCT__entry
+#define TP_STRUCT__entry(args...) args
+
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, args, tstruct, assign, print) \
+       struct ftrace_raw_##name {                              \
+               struct trace_entry      ent;                    \
+               tstruct                                         \
+               char                    __data[0];              \
+       };                                                      \
+       static struct ftrace_event_call event_##name
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+
+/*
+ * Stage 2 of the trace events.
+ *
+ * Include the following:
+ *
+ * struct ftrace_data_offsets_<call> {
+ *     int                             <item1>;
+ *     int                             <item2>;
+ *     [...]
+ * };
+ *
+ * The __dynamic_array() macro will create each int <item>, this is
+ * to keep the offset of each array from the beginning of the event.
+ */
+
+#undef __field
+#define __field(type, item);
+
+#undef __array
+#define __array(type, item, len)
+
+#undef __dynamic_array
+#define __dynamic_array(type, item, len)       int item;
+
+#undef __string
+#define __string(item, src) __dynamic_array(char, item, -1)
+
+#undef TRACE_EVENT
+#define TRACE_EVENT(call, proto, args, tstruct, assign, print)         \
+       struct ftrace_data_offsets_##call {                             \
+               tstruct;                                                \
+       };
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+/*
+ * Setup the showing format of trace point.
+ *
+ * int
+ * ftrace_format_##call(struct trace_seq *s)
+ * {
+ *     struct ftrace_raw_##call field;
+ *     int ret;
+ *
+ *     ret = trace_seq_printf(s, #type " " #item ";"
+ *                            " offset:%u; size:%u;\n",
+ *                            offsetof(struct ftrace_raw_##call, item),
+ *                            sizeof(field.type));
+ *
+ * }
+ */
+
+#undef TP_STRUCT__entry
+#define TP_STRUCT__entry(args...) args
+
+#undef __field
+#define __field(type, item)                                    \
+       ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t"      \
+                              "offset:%u;\tsize:%u;\n",                \
+                              (unsigned int)offsetof(typeof(field), item), \
+                              (unsigned int)sizeof(field.item));       \
+       if (!ret)                                                       \
+               return 0;
+
+#undef __array
+#define __array(type, item, len)                                               \
+       ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t"    \
+                              "offset:%u;\tsize:%u;\n",                \
+                              (unsigned int)offsetof(typeof(field), item), \
+                              (unsigned int)sizeof(field.item));       \
+       if (!ret)                                                       \
+               return 0;
+
+#undef __dynamic_array
+#define __dynamic_array(type, item, len)                                      \
+       ret = trace_seq_printf(s, "\tfield:__data_loc " #item ";\t"            \
+                              "offset:%u;\tsize:%u;\n",                       \
+                              (unsigned int)offsetof(typeof(field),           \
+                                       __data_loc_##item),                    \
+                              (unsigned int)sizeof(field.__data_loc_##item)); \
+       if (!ret)                                                              \
+               return 0;
+
+#undef __string
+#define __string(item, src) __dynamic_array(char, item, -1)
+
+#undef __entry
+#define __entry REC
+
+#undef __print_symbolic
+#undef __get_dynamic_array
+#undef __get_str
+
+#undef TP_printk
+#define TP_printk(fmt, args...) "%s, %s\n", #fmt, __stringify(args)
+
+#undef TP_fast_assign
+#define TP_fast_assign(args...) args
+
+#undef TRACE_EVENT
+#define TRACE_EVENT(call, proto, args, tstruct, func, print)           \
+static int                                                             \
+ftrace_format_##call(struct trace_seq *s)                              \
+{                                                                      \
+       struct ftrace_raw_##call field __attribute__((unused));         \
+       int ret = 0;                                                    \
+                                                                       \
+       tstruct;                                                        \
+                                                                       \
+       trace_seq_printf(s, "\nprint fmt: " print);                     \
+                                                                       \
+       return ret;                                                     \
+}
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+/*
+ * Stage 3 of the trace events.
+ *
+ * Override the macros in <trace/trace_events.h> to include the following:
+ *
+ * enum print_line_t
+ * ftrace_raw_output_<call>(struct trace_iterator *iter, int flags)
+ * {
+ *     struct trace_seq *s = &iter->seq;
+ *     struct ftrace_raw_<call> *field; <-- defined in stage 1
+ *     struct trace_entry *entry;
+ *     struct trace_seq *p;
+ *     int ret;
+ *
+ *     entry = iter->ent;
+ *
+ *     if (entry->type != event_<call>.id) {
+ *             WARN_ON_ONCE(1);
+ *             return TRACE_TYPE_UNHANDLED;
+ *     }
+ *
+ *     field = (typeof(field))entry;
+ *
+ *     p = get_cpu_var(ftrace_event_seq);
+ *     trace_seq_init(p);
+ *     ret = trace_seq_printf(s, <TP_printk> "\n");
+ *     put_cpu();
+ *     if (!ret)
+ *             return TRACE_TYPE_PARTIAL_LINE;
+ *
+ *     return TRACE_TYPE_HANDLED;
+ * }
+ *
+ * This is the method used to print the raw event to the trace
+ * output format. Note, this is not needed if the data is read
+ * in binary.
+ */
+
+#undef __entry
+#define __entry field
+
+#undef TP_printk
+#define TP_printk(fmt, args...) fmt "\n", args
+
+#undef __get_dynamic_array
+#define __get_dynamic_array(field)     \
+               ((void *)__entry + __entry->__data_loc_##field)
+
+#undef __get_str
+#define __get_str(field) (char *)__get_dynamic_array(field)
+
+#undef __print_flags
+#define __print_flags(flag, delim, flag_array...)                      \
+       ({                                                              \
+               static const struct trace_print_flags flags[] =         \
+                       { flag_array, { -1, NULL }};                    \
+               ftrace_print_flags_seq(p, delim, flag, flags);          \
+       })
+
+#undef __print_symbolic
+#define __print_symbolic(value, symbol_array...)                       \
+       ({                                                              \
+               static const struct trace_print_flags symbols[] =       \
+                       { symbol_array, { -1, NULL }};                  \
+               ftrace_print_symbols_seq(p, value, symbols);            \
+       })
+
+#undef TRACE_EVENT
+#define TRACE_EVENT(call, proto, args, tstruct, assign, print)         \
+enum print_line_t                                                      \
+ftrace_raw_output_##call(struct trace_iterator *iter, int flags)       \
+{                                                                      \
+       struct trace_seq *s = &iter->seq;                               \
+       struct ftrace_raw_##call *field;                                \
+       struct trace_entry *entry;                                      \
+       struct trace_seq *p;                                            \
+       int ret;                                                        \
+                                                                       \
+       entry = iter->ent;                                              \
+                                                                       \
+       if (entry->type != event_##call.id) {                           \
+               WARN_ON_ONCE(1);                                        \
+               return TRACE_TYPE_UNHANDLED;                            \
+       }                                                               \
+                                                                       \
+       field = (typeof(field))entry;                                   \
+                                                                       \
+       p = &get_cpu_var(ftrace_event_seq);                             \
+       trace_seq_init(p);                                              \
+       ret = trace_seq_printf(s, #call ": " print);                    \
+       put_cpu();                                                      \
+       if (!ret)                                                       \
+               return TRACE_TYPE_PARTIAL_LINE;                         \
+                                                                       \
+       return TRACE_TYPE_HANDLED;                                      \
+}
+       
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+#undef __field
+#define __field(type, item)                                            \
+       ret = trace_define_field(event_call, #type, #item,              \
+                                offsetof(typeof(field), item),         \
+                                sizeof(field.item), is_signed_type(type));     \
+       if (ret)                                                        \
+               return ret;
+
+#undef __array
+#define __array(type, item, len)                                       \
+       BUILD_BUG_ON(len > MAX_FILTER_STR_VAL);                         \
+       ret = trace_define_field(event_call, #type "[" #len "]", #item, \
+                                offsetof(typeof(field), item),         \
+                                sizeof(field.item), 0);                \
+       if (ret)                                                        \
+               return ret;
+
+#undef __dynamic_array
+#define __dynamic_array(type, item, len)                                      \
+       ret = trace_define_field(event_call, "__data_loc" "[" #type "]", #item,\
+                               offsetof(typeof(field), __data_loc_##item),    \
+                                sizeof(field.__data_loc_##item), 0);
+
+#undef __string
+#define __string(item, src) __dynamic_array(char, item, -1)
+
+#undef TRACE_EVENT
+#define TRACE_EVENT(call, proto, args, tstruct, func, print)           \
+int                                                                    \
+ftrace_define_fields_##call(void)                                      \
+{                                                                      \
+       struct ftrace_raw_##call field;                                 \
+       struct ftrace_event_call *event_call = &event_##call;           \
+       int ret;                                                        \
+                                                                       \
+       __common_field(int, type, 1);                                   \
+       __common_field(unsigned char, flags, 0);                        \
+       __common_field(unsigned char, preempt_count, 0);                \
+       __common_field(int, pid, 1);                                    \
+       __common_field(int, tgid, 1);                                   \
+                                                                       \
+       tstruct;                                                        \
+                                                                       \
+       return ret;                                                     \
+}
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+/*
+ * remember the offset of each array from the beginning of the event.
+ */
+
+#undef __entry
+#define __entry entry
+
+#undef __field
+#define __field(type, item)
+
+#undef __array
+#define __array(type, item, len)
+
+#undef __dynamic_array
+#define __dynamic_array(type, item, len)                               \
+       __data_offsets->item = __data_size +                            \
+                              offsetof(typeof(*entry), __data);        \
+       __data_size += (len) * sizeof(type);
+
+#undef __string
+#define __string(item, src) __dynamic_array(char, item, strlen(src) + 1)       \
+
+#undef TRACE_EVENT
+#define TRACE_EVENT(call, proto, args, tstruct, assign, print)         \
+static inline int ftrace_get_offsets_##call(                           \
+       struct ftrace_data_offsets_##call *__data_offsets, proto)       \
+{                                                                      \
+       int __data_size = 0;                                            \
+       struct ftrace_raw_##call __maybe_unused *entry;                 \
+                                                                       \
+       tstruct;                                                        \
+                                                                       \
+       return __data_size;                                             \
+}
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+/*
+ * Stage 4 of the trace events.
+ *
+ * Override the macros in <trace/trace_events.h> to include the following:
+ *
+ * static void ftrace_event_<call>(proto)
+ * {
+ *     event_trace_printk(_RET_IP_, "<call>: " <fmt>);
+ * }
+ *
+ * static int ftrace_reg_event_<call>(void)
+ * {
+ *     int ret;
+ *
+ *     ret = register_trace_<call>(ftrace_event_<call>);
+ *     if (!ret)
+ *             pr_info("event trace: Could not activate trace point "
+ *                     "probe to  <call>");
+ *     return ret;
+ * }
+ *
+ * static void ftrace_unreg_event_<call>(void)
+ * {
+ *     unregister_trace_<call>(ftrace_event_<call>);
+ * }
+ *
+ *
+ * For those macros defined with TRACE_EVENT:
+ *
+ * static struct ftrace_event_call event_<call>;
+ *
+ * static void ftrace_raw_event_<call>(proto)
+ * {
+ *     struct ring_buffer_event *event;
+ *     struct ftrace_raw_<call> *entry; <-- defined in stage 1
+ *     unsigned long irq_flags;
+ *     int pc;
+ *
+ *     local_save_flags(irq_flags);
+ *     pc = preempt_count();
+ *
+ *     event = trace_current_buffer_lock_reserve(event_<call>.id,
+ *                               sizeof(struct ftrace_raw_<call>),
+ *                               irq_flags, pc);
+ *     if (!event)
+ *             return;
+ *     entry   = ring_buffer_event_data(event);
+ *
+ *     <assign>;  <-- Here we assign the entries by the __field and
+ *                     __array macros.
+ *
+ *     trace_current_buffer_unlock_commit(event, irq_flags, pc);
+ * }
+ *
+ * static int ftrace_raw_reg_event_<call>(void)
+ * {
+ *     int ret;
+ *
+ *     ret = register_trace_<call>(ftrace_raw_event_<call>);
+ *     if (!ret)
+ *             pr_info("event trace: Could not activate trace point "
+ *                     "probe to <call>");
+ *     return ret;
+ * }
+ *
+ * static void ftrace_unreg_event_<call>(void)
+ * {
+ *     unregister_trace_<call>(ftrace_raw_event_<call>);
+ * }
+ *
+ * static struct trace_event ftrace_event_type_<call> = {
+ *     .trace                  = ftrace_raw_output_<call>, <-- stage 2
+ * };
+ *
+ * static int ftrace_raw_init_event_<call>(void)
+ * {
+ *     int id;
+ *
+ *     id = register_ftrace_event(&ftrace_event_type_<call>);
+ *     if (!id)
+ *             return -ENODEV;
+ *     event_<call>.id = id;
+ *     return 0;
+ * }
+ *
+ * static struct ftrace_event_call __used
+ * __attribute__((__aligned__(4)))
+ * __attribute__((section("_ftrace_events"))) event_<call> = {
+ *     .name                   = "<call>",
+ *     .system                 = "<system>",
+ *     .raw_init               = ftrace_raw_init_event_<call>,
+ *     .regfunc                = ftrace_reg_event_<call>,
+ *     .unregfunc              = ftrace_unreg_event_<call>,
+ *     .show_format            = ftrace_format_<call>,
+ * }
+ *
+ */
+
+#undef TP_FMT
+#define TP_FMT(fmt, args...)   fmt "\n", ##args
+
+#ifdef CONFIG_EVENT_PROFILE
+#define _TRACE_PROFILE(call, proto, args)                              \
+static void ftrace_profile_##call(proto)                               \
+{                                                                      \
+       extern void perf_tpcounter_event(int);                          \
+       perf_tpcounter_event(event_##call.id);                          \
+}                                                                      \
+                                                                       \
+static int ftrace_profile_enable_##call(struct ftrace_event_call *event_call) \
+{                                                                      \
+       int ret = 0;                                                    \
+                                                                       \
+       if (!atomic_inc_return(&event_call->profile_count))             \
+               ret = register_trace_##call(ftrace_profile_##call);     \
+                                                                       \
+       return ret;                                                     \
+}                                                                      \
+                                                                       \
+static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\
+{                                                                      \
+       if (atomic_add_negative(-1, &event_call->profile_count))        \
+               unregister_trace_##call(ftrace_profile_##call);         \
+}
+
+#define _TRACE_PROFILE_INIT(call)                                      \
+       .profile_count = ATOMIC_INIT(-1),                               \
+       .profile_enable = ftrace_profile_enable_##call,                 \
+       .profile_disable = ftrace_profile_disable_##call,
+
+#else
+#define _TRACE_PROFILE(call, proto, args)
+#define _TRACE_PROFILE_INIT(call)
+#endif
+
+#undef __entry
+#define __entry entry
+
+#undef __field
+#define __field(type, item)
+
+#undef __array
+#define __array(type, item, len)
+
+#undef __dynamic_array
+#define __dynamic_array(type, item, len)                               \
+       __entry->__data_loc_##item = __data_offsets.item;
+
+#undef __string
+#define __string(item, src) __dynamic_array(char, item, -1)            \
+
+#undef __assign_str
+#define __assign_str(dst, src)                                         \
+       strcpy(__get_str(dst), src);
+
+#undef TRACE_EVENT
+#define TRACE_EVENT(call, proto, args, tstruct, assign, print)         \
+_TRACE_PROFILE(call, PARAMS(proto), PARAMS(args))                      \
+                                                                       \
+static struct ftrace_event_call event_##call;                          \
+                                                                       \
+static void ftrace_raw_event_##call(proto)                             \
+{                                                                      \
+       struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
+       struct ftrace_event_call *event_call = &event_##call;           \
+       struct ring_buffer_event *event;                                \
+       struct ftrace_raw_##call *entry;                                \
+       unsigned long irq_flags;                                        \
+       int __data_size;                                                \
+       int pc;                                                         \
+                                                                       \
+       local_save_flags(irq_flags);                                    \
+       pc = preempt_count();                                           \
+                                                                       \
+       __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
+                                                                       \
+       event = trace_current_buffer_lock_reserve(event_##call.id,      \
+                                sizeof(*entry) + __data_size,          \
+                                irq_flags, pc);                        \
+       if (!event)                                                     \
+               return;                                                 \
+       entry   = ring_buffer_event_data(event);                        \
+                                                                       \
+                                                                       \
+       tstruct                                                         \
+                                                                       \
+       { assign; }                                                     \
+                                                                       \
+       if (!filter_current_check_discard(event_call, entry, event))    \
+               trace_nowake_buffer_unlock_commit(event, irq_flags, pc); \
+}                                                                      \
+                                                                       \
+static int ftrace_raw_reg_event_##call(void)                           \
+{                                                                      \
+       int ret;                                                        \
+                                                                       \
+       ret = register_trace_##call(ftrace_raw_event_##call);           \
+       if (ret)                                                        \
+               pr_info("event trace: Could not activate trace point "  \
+                       "probe to " #call "\n");                        \
+       return ret;                                                     \
+}                                                                      \
+                                                                       \
+static void ftrace_raw_unreg_event_##call(void)                                \
+{                                                                      \
+       unregister_trace_##call(ftrace_raw_event_##call);               \
+}                                                                      \
+                                                                       \
+static struct trace_event ftrace_event_type_##call = {                 \
+       .trace                  = ftrace_raw_output_##call,             \
+};                                                                     \
+                                                                       \
+static int ftrace_raw_init_event_##call(void)                          \
+{                                                                      \
+       int id;                                                         \
+                                                                       \
+       id = register_ftrace_event(&ftrace_event_type_##call);          \
+       if (!id)                                                        \
+               return -ENODEV;                                         \
+       event_##call.id = id;                                           \
+       INIT_LIST_HEAD(&event_##call.fields);                           \
+       init_preds(&event_##call);                                      \
+       return 0;                                                       \
+}                                                                      \
+                                                                       \
+static struct ftrace_event_call __used                                 \
+__attribute__((__aligned__(4)))                                                \
+__attribute__((section("_ftrace_events"))) event_##call = {            \
+       .name                   = #call,                                \
+       .system                 = __stringify(TRACE_SYSTEM),            \
+       .event                  = &ftrace_event_type_##call,            \
+       .raw_init               = ftrace_raw_init_event_##call,         \
+       .regfunc                = ftrace_raw_reg_event_##call,          \
+       .unregfunc              = ftrace_raw_unreg_event_##call,        \
+       .show_format            = ftrace_format_##call,                 \
+       .define_fields          = ftrace_define_fields_##call,          \
+       _TRACE_PROFILE_INIT(call)                                       \
+}
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+#undef _TRACE_PROFILE
+#undef _TRACE_PROFILE_INIT
+
diff --git a/include/trace/irq.h b/include/trace/irq.h
deleted file mode 100644 (file)
index ff5d449..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _TRACE_IRQ_H
-#define _TRACE_IRQ_H
-
-#include <linux/interrupt.h>
-#include <linux/tracepoint.h>
-
-#include <trace/irq_event_types.h>
-
-#endif
diff --git a/include/trace/irq_event_types.h b/include/trace/irq_event_types.h
deleted file mode 100644 (file)
index 85964eb..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-
-/* use <trace/irq.h> instead */
-#ifndef TRACE_FORMAT
-# error Do not include this file directly.
-# error Unless you know what you are doing.
-#endif
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM irq
-
-/*
- * Tracepoint for entry of interrupt handler:
- */
-TRACE_FORMAT(irq_handler_entry,
-       TP_PROTO(int irq, struct irqaction *action),
-       TP_ARGS(irq, action),
-       TP_FMT("irq=%d handler=%s", irq, action->name)
-       );
-
-/*
- * Tracepoint for return of an interrupt handler:
- */
-TRACE_EVENT(irq_handler_exit,
-
-       TP_PROTO(int irq, struct irqaction *action, int ret),
-
-       TP_ARGS(irq, action, ret),
-
-       TP_STRUCT__entry(
-               __field(        int,    irq     )
-               __field(        int,    ret     )
-       ),
-
-       TP_fast_assign(
-               __entry->irq    = irq;
-               __entry->ret    = ret;
-       ),
-
-       TP_printk("irq=%d return=%s",
-                 __entry->irq, __entry->ret ? "handled" : "unhandled")
-);
-
-TRACE_FORMAT(softirq_entry,
-       TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
-       TP_ARGS(h, vec),
-       TP_FMT("softirq=%d action=%s", (int)(h - vec), softirq_to_name[h-vec])
-       );
-
-TRACE_FORMAT(softirq_exit,
-       TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
-       TP_ARGS(h, vec),
-       TP_FMT("softirq=%d action=%s", (int)(h - vec), softirq_to_name[h-vec])
-       );
-
-#undef TRACE_SYSTEM
diff --git a/include/trace/kmemtrace.h b/include/trace/kmemtrace.h
deleted file mode 100644 (file)
index 28ee69f..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2008 Eduard - Gabriel Munteanu
- *
- * This file is released under GPL version 2.
- */
-
-#ifndef _LINUX_KMEMTRACE_H
-#define _LINUX_KMEMTRACE_H
-
-#ifdef __KERNEL__
-
-#include <linux/tracepoint.h>
-#include <linux/types.h>
-
-#ifdef CONFIG_KMEMTRACE
-extern void kmemtrace_init(void);
-#else
-static inline void kmemtrace_init(void)
-{
-}
-#endif
-
-DECLARE_TRACE(kmalloc,
-             TP_PROTO(unsigned long call_site,
-                     const void *ptr,
-                     size_t bytes_req,
-                     size_t bytes_alloc,
-                     gfp_t gfp_flags),
-             TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags));
-DECLARE_TRACE(kmem_cache_alloc,
-             TP_PROTO(unsigned long call_site,
-                     const void *ptr,
-                     size_t bytes_req,
-                     size_t bytes_alloc,
-                     gfp_t gfp_flags),
-             TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags));
-DECLARE_TRACE(kmalloc_node,
-             TP_PROTO(unsigned long call_site,
-                     const void *ptr,
-                     size_t bytes_req,
-                     size_t bytes_alloc,
-                     gfp_t gfp_flags,
-                     int node),
-             TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags, node));
-DECLARE_TRACE(kmem_cache_alloc_node,
-             TP_PROTO(unsigned long call_site,
-                     const void *ptr,
-                     size_t bytes_req,
-                     size_t bytes_alloc,
-                     gfp_t gfp_flags,
-                     int node),
-             TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags, node));
-DECLARE_TRACE(kfree,
-             TP_PROTO(unsigned long call_site, const void *ptr),
-             TP_ARGS(call_site, ptr));
-DECLARE_TRACE(kmem_cache_free,
-             TP_PROTO(unsigned long call_site, const void *ptr),
-             TP_ARGS(call_site, ptr));
-
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_KMEMTRACE_H */
-
diff --git a/include/trace/lockdep.h b/include/trace/lockdep.h
deleted file mode 100644 (file)
index 5ca67df..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _TRACE_LOCKDEP_H
-#define _TRACE_LOCKDEP_H
-
-#include <linux/lockdep.h>
-#include <linux/tracepoint.h>
-
-#include <trace/lockdep_event_types.h>
-
-#endif
diff --git a/include/trace/lockdep_event_types.h b/include/trace/lockdep_event_types.h
deleted file mode 100644 (file)
index adccfcd..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-
-#ifndef TRACE_FORMAT
-# error Do not include this file directly.
-# error Unless you know what you are doing.
-#endif
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM lock
-
-#ifdef CONFIG_LOCKDEP
-
-TRACE_FORMAT(lock_acquire,
-       TP_PROTO(struct lockdep_map *lock, unsigned int subclass,
-               int trylock, int read, int check,
-               struct lockdep_map *next_lock, unsigned long ip),
-       TP_ARGS(lock, subclass, trylock, read, check, next_lock, ip),
-       TP_FMT("%s%s%s", trylock ? "try " : "",
-               read ? "read " : "", lock->name)
-       );
-
-TRACE_FORMAT(lock_release,
-       TP_PROTO(struct lockdep_map *lock, int nested, unsigned long ip),
-       TP_ARGS(lock, nested, ip),
-       TP_FMT("%s", lock->name)
-       );
-
-#ifdef CONFIG_LOCK_STAT
-
-TRACE_FORMAT(lock_contended,
-       TP_PROTO(struct lockdep_map *lock, unsigned long ip),
-       TP_ARGS(lock, ip),
-       TP_FMT("%s", lock->name)
-       );
-
-TRACE_FORMAT(lock_acquired,
-       TP_PROTO(struct lockdep_map *lock, unsigned long ip),
-       TP_ARGS(lock, ip),
-       TP_FMT("%s", lock->name)
-       );
-
-#endif
-#endif
-
-#undef TRACE_SYSTEM
diff --git a/include/trace/sched.h b/include/trace/sched.h
deleted file mode 100644 (file)
index 4e372a1..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _TRACE_SCHED_H
-#define _TRACE_SCHED_H
-
-#include <linux/sched.h>
-#include <linux/tracepoint.h>
-
-#include <trace/sched_event_types.h>
-
-#endif
diff --git a/include/trace/skb.h b/include/trace/skb.h
deleted file mode 100644 (file)
index b66206d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _TRACE_SKB_H_
-#define _TRACE_SKB_H_
-
-#include <linux/skbuff.h>
-#include <linux/tracepoint.h>
-
-DECLARE_TRACE(kfree_skb,
-       TP_PROTO(struct sk_buff *skb, void *location),
-       TP_ARGS(skb, location));
-
-#endif
diff --git a/include/trace/trace_event_types.h b/include/trace/trace_event_types.h
deleted file mode 100644 (file)
index df56f56..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-/* trace/<type>_event_types.h here */
-
-#include <trace/sched_event_types.h>
-#include <trace/irq_event_types.h>
-#include <trace/lockdep_event_types.h>
diff --git a/include/trace/trace_events.h b/include/trace/trace_events.h
deleted file mode 100644 (file)
index fd13750..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-/* trace/<type>.h here */
-
-#include <trace/sched.h>
-#include <trace/irq.h>
-#include <trace/lockdep.h>
diff --git a/include/trace/workqueue.h b/include/trace/workqueue.h
deleted file mode 100644 (file)
index 7626523..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __TRACE_WORKQUEUE_H
-#define __TRACE_WORKQUEUE_H
-
-#include <linux/tracepoint.h>
-#include <linux/workqueue.h>
-#include <linux/sched.h>
-
-DECLARE_TRACE(workqueue_insertion,
-          TP_PROTO(struct task_struct *wq_thread, struct work_struct *work),
-          TP_ARGS(wq_thread, work));
-
-DECLARE_TRACE(workqueue_execution,
-          TP_PROTO(struct task_struct *wq_thread, struct work_struct *work),
-          TP_ARGS(wq_thread, work));
-
-/* Trace the creation of one workqueue thread on a cpu */
-DECLARE_TRACE(workqueue_creation,
-          TP_PROTO(struct task_struct *wq_thread, int cpu),
-          TP_ARGS(wq_thread, cpu));
-
-DECLARE_TRACE(workqueue_destruction,
-          TP_PROTO(struct task_struct *wq_thread),
-          TP_ARGS(wq_thread));
-
-#endif /* __TRACE_WORKQUEUE_H */
diff --git a/include/xen/Kbuild b/include/xen/Kbuild
new file mode 100644 (file)
index 0000000..4e65c16
--- /dev/null
@@ -0,0 +1 @@
+header-y += evtchn.h
index 0d5f1adc0363e9e125cb8786ca96b0917440b6b5..e68d59a90ca88b73c21b431c3cf538165916d5a7 100644 (file)
@@ -53,4 +53,7 @@ bool xen_test_irq_pending(int irq);
    irq will be disabled so it won't deliver an interrupt. */
 void xen_poll_irq(int irq);
 
+/* Determine the IRQ which is bound to an event channel */
+unsigned irq_from_evtchn(unsigned int evtchn);
+
 #endif /* _XEN_EVENTS_H */
diff --git a/include/xen/evtchn.h b/include/xen/evtchn.h
new file mode 100644 (file)
index 0000000..14e833e
--- /dev/null
@@ -0,0 +1,88 @@
+/******************************************************************************
+ * evtchn.h
+ *
+ * Interface to /dev/xen/evtchn.
+ *
+ * Copyright (c) 2003-2005, K A Fraser
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __LINUX_PUBLIC_EVTCHN_H__
+#define __LINUX_PUBLIC_EVTCHN_H__
+
+/*
+ * Bind a fresh port to VIRQ @virq.
+ * Return allocated port.
+ */
+#define IOCTL_EVTCHN_BIND_VIRQ                         \
+       _IOC(_IOC_NONE, 'E', 0, sizeof(struct ioctl_evtchn_bind_virq))
+struct ioctl_evtchn_bind_virq {
+       unsigned int virq;
+};
+
+/*
+ * Bind a fresh port to remote <@remote_domain, @remote_port>.
+ * Return allocated port.
+ */
+#define IOCTL_EVTCHN_BIND_INTERDOMAIN                  \
+       _IOC(_IOC_NONE, 'E', 1, sizeof(struct ioctl_evtchn_bind_interdomain))
+struct ioctl_evtchn_bind_interdomain {
+       unsigned int remote_domain, remote_port;
+};
+
+/*
+ * Allocate a fresh port for binding to @remote_domain.
+ * Return allocated port.
+ */
+#define IOCTL_EVTCHN_BIND_UNBOUND_PORT                 \
+       _IOC(_IOC_NONE, 'E', 2, sizeof(struct ioctl_evtchn_bind_unbound_port))
+struct ioctl_evtchn_bind_unbound_port {
+       unsigned int remote_domain;
+};
+
+/*
+ * Unbind previously allocated @port.
+ */
+#define IOCTL_EVTCHN_UNBIND                            \
+       _IOC(_IOC_NONE, 'E', 3, sizeof(struct ioctl_evtchn_unbind))
+struct ioctl_evtchn_unbind {
+       unsigned int port;
+};
+
+/*
+ * Unbind previously allocated @port.
+ */
+#define IOCTL_EVTCHN_NOTIFY                            \
+       _IOC(_IOC_NONE, 'E', 4, sizeof(struct ioctl_evtchn_notify))
+struct ioctl_evtchn_notify {
+       unsigned int port;
+};
+
+/* Clear and reinitialise the event buffer. Clear error condition. */
+#define IOCTL_EVTCHN_RESET                             \
+       _IOC(_IOC_NONE, 'E', 5, 0)
+
+#endif /* __LINUX_PUBLIC_EVTCHN_H__ */
index 453235e923f0be0d3ae801e754bfb83a68caf892..e8b6519d47e9df818ebbb6d19323f032b8dde988 100644 (file)
@@ -57,4 +57,7 @@ struct xen_feature_info {
 /* Declares the features reported by XENVER_get_features. */
 #include "features.h"
 
+/* arg == NULL; returns host memory page size. */
+#define XENVER_pagesize 7
+
 #endif /* __XEN_PUBLIC_VERSION_H__ */
index f87f9614844db69e7eeacb2784646f5458ed954a..b9763badbd77da07813dae421f20a90a08df2e11 100644 (file)
@@ -91,8 +91,7 @@ struct xenbus_driver {
        void (*otherend_changed)(struct xenbus_device *dev,
                                 enum xenbus_state backend_state);
        int (*remove)(struct xenbus_device *dev);
-       int (*suspend)(struct xenbus_device *dev);
-       int (*suspend_cancel)(struct xenbus_device *dev);
+       int (*suspend)(struct xenbus_device *dev, pm_message_t state);
        int (*resume)(struct xenbus_device *dev);
        int (*uevent)(struct xenbus_device *, char **, int, char *, int);
        struct device_driver driver;
index 7be4d3836745a049596e7be06b5e850c035b1f72..d4e9671347ee907ba9f59f5a87f0e446970b9725 100644 (file)
@@ -308,7 +308,7 @@ menu "RCU Subsystem"
 
 choice
        prompt "RCU Implementation"
-       default CLASSIC_RCU
+       default TREE_RCU
 
 config CLASSIC_RCU
        bool "Classic RCU"
index d721dad05dd722fa065170e9f573a4f74c49d38d..bb7dc57eee36ed8079e63bdf1a4c725d4c97e45f 100644 (file)
@@ -64,6 +64,7 @@
 #include <linux/idr.h>
 #include <linux/ftrace.h>
 #include <linux/async.h>
+#include <linux/kmemtrace.h>
 #include <trace/boot.h>
 
 #include <asm/io.h>
@@ -71,7 +72,6 @@
 #include <asm/setup.h>
 #include <asm/sections.h>
 #include <asm/cacheflush.h>
-#include <trace/kmemtrace.h>
 
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/smp.h>
index 16a2189e96f9458d7626660b4c537dd718bd0fd6..87c2b641fd7b475b192adf281fcdc1f5cf249893 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1290,8 +1290,8 @@ void exit_sem(struct task_struct *tsk)
                int i;
 
                rcu_read_lock();
-               un = list_entry(rcu_dereference(ulp->list_proc.next),
-                                       struct sem_undo, list_proc);
+               un = list_entry_rcu(ulp->list_proc.next,
+                                   struct sem_undo, list_proc);
                if (&un->list_proc == &ulp->list_proc)
                        semid = -1;
                 else
index 4259716004853bf727491980208e01686958085b..15dd238e533887b1e84f17b070bb64f0b4660961 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -384,7 +384,6 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
        error = PTR_ERR(file);
        if (IS_ERR(file))
                goto no_file;
-       ima_shm_check(file);
 
        id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
        if (id < 0) {
@@ -891,7 +890,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
        file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations);
        if (!file)
                goto out_free;
-       ima_shm_check(file);
+       ima_counts_get(file);
 
        file->private_data = sfd;
        file->f_mapping = shp->shm_file->f_mapping;
index 42423665660a3d6e0a1fc6a37dd0da997643b47f..a35eee3436de081a7a35d9b8184a9349facee17d 100644 (file)
@@ -93,6 +93,7 @@ obj-$(CONFIG_LATENCYTOP) += latencytop.o
 obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
 obj-$(CONFIG_FUNCTION_TRACER) += trace/
 obj-$(CONFIG_TRACING) += trace/
+obj-$(CONFIG_X86_DS) += trace/
 obj-$(CONFIG_SMP) += sched_cpupri.o
 obj-$(CONFIG_SLOW_WORK) += slow-work.o
 
index 42d56544460f21b353cc279aa8aa52301eded59b..f6c204f07ea6084c4849d52358d6b1b2aab1f0da 100644 (file)
@@ -882,6 +882,17 @@ compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese,
 
 }
 
+asmlinkage long
+compat_sys_rt_tgsigqueueinfo(compat_pid_t tgid, compat_pid_t pid, int sig,
+                            struct compat_siginfo __user *uinfo)
+{
+       siginfo_t info;
+
+       if (copy_siginfo_from_user32(&info, uinfo))
+               return -EFAULT;
+       return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);
+}
+
 #ifdef __ARCH_WANT_COMPAT_SYS_TIME
 
 /* compat_time_t is a 32 bit "long" and needs to get converted. */
index 3a039189d70748b294082301d9636d467c019c3b..1bb4d7e5d61694a6b8c01ba47f8432dcd37c828e 100644 (file)
@@ -167,7 +167,7 @@ EXPORT_SYMBOL(prepare_creds);
 
 /*
  * Prepare credentials for current to perform an execve()
- * - The caller must hold current->cred_exec_mutex
+ * - The caller must hold current->cred_guard_mutex
  */
 struct cred *prepare_exec_creds(void)
 {
@@ -276,7 +276,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
        struct cred *new;
        int ret;
 
-       mutex_init(&p->cred_exec_mutex);
+       mutex_init(&p->cred_guard_mutex);
 
        if (
 #ifdef CONFIG_KEYS
index abf9cf3b95c609f12ccb0c6992cc3a8221bdcf8b..51d1fe3fb7ad5b60666c7f229d6bacd8942479e9 100644 (file)
@@ -48,7 +48,7 @@
 #include <linux/tracehook.h>
 #include <linux/fs_struct.h>
 #include <linux/init_task.h>
-#include <trace/sched.h>
+#include <trace/events/sched.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include <asm/mmu_context.h>
 #include "cred-internals.h"
 
-DEFINE_TRACE(sched_process_free);
-DEFINE_TRACE(sched_process_exit);
-DEFINE_TRACE(sched_process_wait);
-
 static void exit_mm(struct task_struct * tsk);
 
 static void __unhash_process(struct task_struct *p)
@@ -1476,6 +1472,7 @@ static int wait_consider_task(struct task_struct *parent, int ptrace,
                 */
                if (*notask_error)
                        *notask_error = ret;
+               return 0;
        }
 
        if (likely(!ptrace) && unlikely(p->ptrace)) {
index 875ffbdd96d09ccb2a9587636f472b8b8278cbfd..bb762b4dd21769e9c4035128b2317ca643818a1b 100644 (file)
@@ -61,7 +61,6 @@
 #include <linux/proc_fs.h>
 #include <linux/blkdev.h>
 #include <linux/fs_struct.h>
-#include <trace/sched.h>
 #include <linux/magic.h>
 
 #include <asm/pgtable.h>
@@ -71,6 +70,8 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
+#include <trace/events/sched.h>
+
 /*
  * Protected counters by write_lock_irq(&tasklist_lock)
  */
@@ -83,8 +84,6 @@ DEFINE_PER_CPU(unsigned long, process_counts) = 0;
 
 __cacheline_aligned DEFINE_RWLOCK(tasklist_lock);  /* outer */
 
-DEFINE_TRACE(sched_process_fork);
-
 int nr_processes(void)
 {
        int cpu;
@@ -982,6 +981,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        if (!p)
                goto fork_out;
 
+       ftrace_graph_init_task(p);
+
        rt_mutex_init_task(p);
 
 #ifdef CONFIG_PROVE_LOCKING
@@ -1089,8 +1090,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 #ifdef CONFIG_DEBUG_MUTEXES
        p->blocked_on = NULL; /* not blocked yet */
 #endif
-       if (unlikely(current->ptrace))
-               ptrace_fork(p, clone_flags);
+
+       p->bts = NULL;
 
        /* Perform scheduler related setup. Assign this task to a CPU. */
        sched_fork(p, clone_flags);
@@ -1131,8 +1132,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                }
        }
 
-       ftrace_graph_init_task(p);
-
        p->pid = pid_nr(pid);
        p->tgid = p->pid;
        if (clone_flags & CLONE_THREAD)
@@ -1141,7 +1140,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        if (current->nsproxy != p->nsproxy) {
                retval = ns_cgroup_clone(p, pid);
                if (retval)
-                       goto bad_fork_free_graph;
+                       goto bad_fork_free_pid;
        }
 
        p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
@@ -1233,7 +1232,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                spin_unlock(&current->sighand->siglock);
                write_unlock_irq(&tasklist_lock);
                retval = -ERESTARTNOINTR;
-               goto bad_fork_free_graph;
+               goto bad_fork_free_pid;
        }
 
        if (clone_flags & CLONE_THREAD) {
@@ -1268,8 +1267,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        cgroup_post_fork(p);
        return p;
 
-bad_fork_free_graph:
-       ftrace_graph_exit_task(p);
 bad_fork_free_pid:
        if (pid != &init_struct_pid)
                free_pid(pid);
index d546b2d53a62ba700756c8b7ff53b11373923162..80b5ce716596a95b797a00c417b5a514f9d5d2a2 100644 (file)
  *  PRIVATE futexes by Eric Dumazet
  *  Copyright (C) 2007 Eric Dumazet <dada1@cosmosbay.com>
  *
+ *  Requeue-PI support by Darren Hart <dvhltc@us.ibm.com>
+ *  Copyright (C) IBM Corporation, 2009
+ *  Thanks to Thomas Gleixner for conceptual design and careful reviews.
+ *
  *  Thanks to Ben LaHaise for yelling "hashed waitqueues" loudly
  *  enough at me, Linus for the original (flawed) idea, Matthew
  *  Kirkwood for proof-of-concept implementation.
@@ -96,8 +100,8 @@ struct futex_pi_state {
  */
 struct futex_q {
        struct plist_node list;
-       /* There can only be a single waiter */
-       wait_queue_head_t waiter;
+       /* Waiter reference */
+       struct task_struct *task;
 
        /* Which hash list lock to use: */
        spinlock_t *lock_ptr;
@@ -107,7 +111,9 @@ struct futex_q {
 
        /* Optional priority inheritance state: */
        struct futex_pi_state *pi_state;
-       struct task_struct *task;
+
+       /* rt_waiter storage for requeue_pi: */
+       struct rt_mutex_waiter *rt_waiter;
 
        /* Bitset for the optional bitmasked wakeup */
        u32 bitset;
@@ -278,6 +284,25 @@ void put_futex_key(int fshared, union futex_key *key)
        drop_futex_key_refs(key);
 }
 
+/**
+ * futex_top_waiter() - Return the highest priority waiter on a futex
+ * @hb:     the hash bucket the futex_q's reside in
+ * @key:    the futex key (to distinguish it from other futex futex_q's)
+ *
+ * Must be called with the hb lock held.
+ */
+static struct futex_q *futex_top_waiter(struct futex_hash_bucket *hb,
+                                       union futex_key *key)
+{
+       struct futex_q *this;
+
+       plist_for_each_entry(this, &hb->chain, list) {
+               if (match_futex(&this->key, key))
+                       return this;
+       }
+       return NULL;
+}
+
 static u32 cmpxchg_futex_value_locked(u32 __user *uaddr, u32 uval, u32 newval)
 {
        u32 curval;
@@ -539,28 +564,160 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
        return 0;
 }
 
+/**
+ * futex_lock_pi_atomic() - atomic work required to acquire a pi aware futex
+ * @uaddr:             the pi futex user address
+ * @hb:                        the pi futex hash bucket
+ * @key:               the futex key associated with uaddr and hb
+ * @ps:                        the pi_state pointer where we store the result of the
+ *                     lookup
+ * @task:              the task to perform the atomic lock work for.  This will
+ *                     be "current" except in the case of requeue pi.
+ * @set_waiters:       force setting the FUTEX_WAITERS bit (1) or not (0)
+ *
+ * Returns:
+ *  0 - ready to wait
+ *  1 - acquired the lock
+ * <0 - error
+ *
+ * The hb->lock and futex_key refs shall be held by the caller.
+ */
+static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb,
+                               union futex_key *key,
+                               struct futex_pi_state **ps,
+                               struct task_struct *task, int set_waiters)
+{
+       int lock_taken, ret, ownerdied = 0;
+       u32 uval, newval, curval;
+
+retry:
+       ret = lock_taken = 0;
+
+       /*
+        * To avoid races, we attempt to take the lock here again
+        * (by doing a 0 -> TID atomic cmpxchg), while holding all
+        * the locks. It will most likely not succeed.
+        */
+       newval = task_pid_vnr(task);
+       if (set_waiters)
+               newval |= FUTEX_WAITERS;
+
+       curval = cmpxchg_futex_value_locked(uaddr, 0, newval);
+
+       if (unlikely(curval == -EFAULT))
+               return -EFAULT;
+
+       /*
+        * Detect deadlocks.
+        */
+       if ((unlikely((curval & FUTEX_TID_MASK) == task_pid_vnr(task))))
+               return -EDEADLK;
+
+       /*
+        * Surprise - we got the lock. Just return to userspace:
+        */
+       if (unlikely(!curval))
+               return 1;
+
+       uval = curval;
+
+       /*
+        * Set the FUTEX_WAITERS flag, so the owner will know it has someone
+        * to wake at the next unlock.
+        */
+       newval = curval | FUTEX_WAITERS;
+
+       /*
+        * There are two cases, where a futex might have no owner (the
+        * owner TID is 0): OWNER_DIED. We take over the futex in this
+        * case. We also do an unconditional take over, when the owner
+        * of the futex died.
+        *
+        * This is safe as we are protected by the hash bucket lock !
+        */
+       if (unlikely(ownerdied || !(curval & FUTEX_TID_MASK))) {
+               /* Keep the OWNER_DIED bit */
+               newval = (curval & ~FUTEX_TID_MASK) | task_pid_vnr(task);
+               ownerdied = 0;
+               lock_taken = 1;
+       }
+
+       curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
+
+       if (unlikely(curval == -EFAULT))
+               return -EFAULT;
+       if (unlikely(curval != uval))
+               goto retry;
+
+       /*
+        * We took the lock due to owner died take over.
+        */
+       if (unlikely(lock_taken))
+               return 1;
+
+       /*
+        * We dont have the lock. Look up the PI state (or create it if
+        * we are the first waiter):
+        */
+       ret = lookup_pi_state(uval, hb, key, ps);
+
+       if (unlikely(ret)) {
+               switch (ret) {
+               case -ESRCH:
+                       /*
+                        * No owner found for this futex. Check if the
+                        * OWNER_DIED bit is set to figure out whether
+                        * this is a robust futex or not.
+                        */
+                       if (get_futex_value_locked(&curval, uaddr))
+                               return -EFAULT;
+
+                       /*
+                        * We simply start over in case of a robust
+                        * futex. The code above will take the futex
+                        * and return happy.
+                        */
+                       if (curval & FUTEX_OWNER_DIED) {
+                               ownerdied = 1;
+                               goto retry;
+                       }
+               default:
+                       break;
+               }
+       }
+
+       return ret;
+}
+
 /*
  * The hash bucket lock must be held when this is called.
  * Afterwards, the futex_q must not be accessed.
  */
 static void wake_futex(struct futex_q *q)
 {
-       plist_del(&q->list, &q->list.plist);
+       struct task_struct *p = q->task;
+
        /*
-        * The lock in wake_up_all() is a crucial memory barrier after the
-        * plist_del() and also before assigning to q->lock_ptr.
+        * We set q->lock_ptr = NULL _before_ we wake up the task. If
+        * a non futex wake up happens on another CPU then the task
+        * might exit and p would dereference a non existing task
+        * struct. Prevent this by holding a reference on p across the
+        * wake up.
         */
-       wake_up(&q->waiter);
+       get_task_struct(p);
+
+       plist_del(&q->list, &q->list.plist);
        /*
-        * The waiting task can free the futex_q as soon as this is written,
-        * without taking any locks.  This must come last.
-        *
-        * A memory barrier is required here to prevent the following store to
-        * lock_ptr from getting ahead of the wakeup. Clearing the lock at the
-        * end of wake_up() does not prevent this store from moving.
+        * The waiting task can free the futex_q as soon as
+        * q->lock_ptr = NULL is written, without taking any locks. A
+        * memory barrier is required here to prevent the following
+        * store to lock_ptr from getting ahead of the plist_del.
         */
        smp_wmb();
        q->lock_ptr = NULL;
+
+       wake_up_state(p, TASK_NORMAL);
+       put_task_struct(p);
 }
 
 static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
@@ -689,7 +846,7 @@ static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset)
 
        plist_for_each_entry_safe(this, next, head, list) {
                if (match_futex (&this->key, &key)) {
-                       if (this->pi_state) {
+                       if (this->pi_state || this->rt_waiter) {
                                ret = -EINVAL;
                                break;
                        }
@@ -802,24 +959,185 @@ out:
        return ret;
 }
 
-/*
- * Requeue all waiters hashed on one physical page to another
- * physical page.
+/**
+ * requeue_futex() - Requeue a futex_q from one hb to another
+ * @q:         the futex_q to requeue
+ * @hb1:       the source hash_bucket
+ * @hb2:       the target hash_bucket
+ * @key2:      the new key for the requeued futex_q
+ */
+static inline
+void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1,
+                  struct futex_hash_bucket *hb2, union futex_key *key2)
+{
+
+       /*
+        * If key1 and key2 hash to the same bucket, no need to
+        * requeue.
+        */
+       if (likely(&hb1->chain != &hb2->chain)) {
+               plist_del(&q->list, &hb1->chain);
+               plist_add(&q->list, &hb2->chain);
+               q->lock_ptr = &hb2->lock;
+#ifdef CONFIG_DEBUG_PI_LIST
+               q->list.plist.lock = &hb2->lock;
+#endif
+       }
+       get_futex_key_refs(key2);
+       q->key = *key2;
+}
+
+/**
+ * requeue_pi_wake_futex() - Wake a task that acquired the lock during requeue
+ * q:  the futex_q
+ * key:        the key of the requeue target futex
+ *
+ * During futex_requeue, with requeue_pi=1, it is possible to acquire the
+ * target futex if it is uncontended or via a lock steal.  Set the futex_q key
+ * to the requeue target futex so the waiter can detect the wakeup on the right
+ * futex, but remove it from the hb and NULL the rt_waiter so it can detect
+ * atomic lock acquisition.  Must be called with the q->lock_ptr held.
+ */
+static inline
+void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key)
+{
+       drop_futex_key_refs(&q->key);
+       get_futex_key_refs(key);
+       q->key = *key;
+
+       WARN_ON(plist_node_empty(&q->list));
+       plist_del(&q->list, &q->list.plist);
+
+       WARN_ON(!q->rt_waiter);
+       q->rt_waiter = NULL;
+
+       wake_up_state(q->task, TASK_NORMAL);
+}
+
+/**
+ * futex_proxy_trylock_atomic() - Attempt an atomic lock for the top waiter
+ * @pifutex:           the user address of the to futex
+ * @hb1:               the from futex hash bucket, must be locked by the caller
+ * @hb2:               the to futex hash bucket, must be locked by the caller
+ * @key1:              the from futex key
+ * @key2:              the to futex key
+ * @ps:                        address to store the pi_state pointer
+ * @set_waiters:       force setting the FUTEX_WAITERS bit (1) or not (0)
+ *
+ * Try and get the lock on behalf of the top waiter if we can do it atomically.
+ * Wake the top waiter if we succeed.  If the caller specified set_waiters,
+ * then direct futex_lock_pi_atomic() to force setting the FUTEX_WAITERS bit.
+ * hb1 and hb2 must be held by the caller.
+ *
+ * Returns:
+ *  0 - failed to acquire the lock atomicly
+ *  1 - acquired the lock
+ * <0 - error
+ */
+static int futex_proxy_trylock_atomic(u32 __user *pifutex,
+                                struct futex_hash_bucket *hb1,
+                                struct futex_hash_bucket *hb2,
+                                union futex_key *key1, union futex_key *key2,
+                                struct futex_pi_state **ps, int set_waiters)
+{
+       struct futex_q *top_waiter = NULL;
+       u32 curval;
+       int ret;
+
+       if (get_futex_value_locked(&curval, pifutex))
+               return -EFAULT;
+
+       /*
+        * Find the top_waiter and determine if there are additional waiters.
+        * If the caller intends to requeue more than 1 waiter to pifutex,
+        * force futex_lock_pi_atomic() to set the FUTEX_WAITERS bit now,
+        * as we have means to handle the possible fault.  If not, don't set
+        * the bit unecessarily as it will force the subsequent unlock to enter
+        * the kernel.
+        */
+       top_waiter = futex_top_waiter(hb1, key1);
+
+       /* There are no waiters, nothing for us to do. */
+       if (!top_waiter)
+               return 0;
+
+       /*
+        * Try to take the lock for top_waiter.  Set the FUTEX_WAITERS bit in
+        * the contended case or if set_waiters is 1.  The pi_state is returned
+        * in ps in contended cases.
+        */
+       ret = futex_lock_pi_atomic(pifutex, hb2, key2, ps, top_waiter->task,
+                                  set_waiters);
+       if (ret == 1)
+               requeue_pi_wake_futex(top_waiter, key2);
+
+       return ret;
+}
+
+/**
+ * futex_requeue() - Requeue waiters from uaddr1 to uaddr2
+ * uaddr1:     source futex user address
+ * uaddr2:     target futex user address
+ * nr_wake:    number of waiters to wake (must be 1 for requeue_pi)
+ * nr_requeue: number of waiters to requeue (0-INT_MAX)
+ * requeue_pi: if we are attempting to requeue from a non-pi futex to a
+ *             pi futex (pi to pi requeue is not supported)
+ *
+ * Requeue waiters on uaddr1 to uaddr2. In the requeue_pi case, try to acquire
+ * uaddr2 atomically on behalf of the top waiter.
+ *
+ * Returns:
+ * >=0 - on success, the number of tasks requeued or woken
+ *  <0 - on error
  */
 static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
-                        int nr_wake, int nr_requeue, u32 *cmpval)
+                        int nr_wake, int nr_requeue, u32 *cmpval,
+                        int requeue_pi)
 {
        union futex_key key1 = FUTEX_KEY_INIT, key2 = FUTEX_KEY_INIT;
+       int drop_count = 0, task_count = 0, ret;
+       struct futex_pi_state *pi_state = NULL;
        struct futex_hash_bucket *hb1, *hb2;
        struct plist_head *head1;
        struct futex_q *this, *next;
-       int ret, drop_count = 0;
+       u32 curval2;
+
+       if (requeue_pi) {
+               /*
+                * requeue_pi requires a pi_state, try to allocate it now
+                * without any locks in case it fails.
+                */
+               if (refill_pi_state_cache())
+                       return -ENOMEM;
+               /*
+                * requeue_pi must wake as many tasks as it can, up to nr_wake
+                * + nr_requeue, since it acquires the rt_mutex prior to
+                * returning to userspace, so as to not leave the rt_mutex with
+                * waiters and no owner.  However, second and third wake-ups
+                * cannot be predicted as they involve race conditions with the
+                * first wake and a fault while looking up the pi_state.  Both
+                * pthread_cond_signal() and pthread_cond_broadcast() should
+                * use nr_wake=1.
+                */
+               if (nr_wake != 1)
+                       return -EINVAL;
+       }
 
 retry:
+       if (pi_state != NULL) {
+               /*
+                * We will have to lookup the pi_state again, so free this one
+                * to keep the accounting correct.
+                */
+               free_pi_state(pi_state);
+               pi_state = NULL;
+       }
+
        ret = get_futex_key(uaddr1, fshared, &key1, VERIFY_READ);
        if (unlikely(ret != 0))
                goto out;
-       ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_READ);
+       ret = get_futex_key(uaddr2, fshared, &key2,
+                           requeue_pi ? VERIFY_WRITE : VERIFY_READ);
        if (unlikely(ret != 0))
                goto out_put_key1;
 
@@ -854,32 +1172,99 @@ retry_private:
                }
        }
 
+       if (requeue_pi && (task_count - nr_wake < nr_requeue)) {
+               /*
+                * Attempt to acquire uaddr2 and wake the top waiter. If we
+                * intend to requeue waiters, force setting the FUTEX_WAITERS
+                * bit.  We force this here where we are able to easily handle
+                * faults rather in the requeue loop below.
+                */
+               ret = futex_proxy_trylock_atomic(uaddr2, hb1, hb2, &key1,
+                                                &key2, &pi_state, nr_requeue);
+
+               /*
+                * At this point the top_waiter has either taken uaddr2 or is
+                * waiting on it.  If the former, then the pi_state will not
+                * exist yet, look it up one more time to ensure we have a
+                * reference to it.
+                */
+               if (ret == 1) {
+                       WARN_ON(pi_state);
+                       task_count++;
+                       ret = get_futex_value_locked(&curval2, uaddr2);
+                       if (!ret)
+                               ret = lookup_pi_state(curval2, hb2, &key2,
+                                                     &pi_state);
+               }
+
+               switch (ret) {
+               case 0:
+                       break;
+               case -EFAULT:
+                       double_unlock_hb(hb1, hb2);
+                       put_futex_key(fshared, &key2);
+                       put_futex_key(fshared, &key1);
+                       ret = get_user(curval2, uaddr2);
+                       if (!ret)
+                               goto retry;
+                       goto out;
+               case -EAGAIN:
+                       /* The owner was exiting, try again. */
+                       double_unlock_hb(hb1, hb2);
+                       put_futex_key(fshared, &key2);
+                       put_futex_key(fshared, &key1);
+                       cond_resched();
+                       goto retry;
+               default:
+                       goto out_unlock;
+               }
+       }
+
        head1 = &hb1->chain;
        plist_for_each_entry_safe(this, next, head1, list) {
-               if (!match_futex (&this->key, &key1))
+               if (task_count - nr_wake >= nr_requeue)
+                       break;
+
+               if (!match_futex(&this->key, &key1))
                        continue;
-               if (++ret <= nr_wake) {
+
+               WARN_ON(!requeue_pi && this->rt_waiter);
+               WARN_ON(requeue_pi && !this->rt_waiter);
+
+               /*
+                * Wake nr_wake waiters.  For requeue_pi, if we acquired the
+                * lock, we already woke the top_waiter.  If not, it will be
+                * woken by futex_unlock_pi().
+                */
+               if (++task_count <= nr_wake && !requeue_pi) {
                        wake_futex(this);
-               } else {
-                       /*
-                        * If key1 and key2 hash to the same bucket, no need to
-                        * requeue.
-                        */
-                       if (likely(head1 != &hb2->chain)) {
-                               plist_del(&this->list, &hb1->chain);
-                               plist_add(&this->list, &hb2->chain);
-                               this->lock_ptr = &hb2->lock;
-#ifdef CONFIG_DEBUG_PI_LIST
-                               this->list.plist.lock = &hb2->lock;
-#endif
-                       }
-                       this->key = key2;
-                       get_futex_key_refs(&key2);
-                       drop_count++;
+                       continue;
+               }
 
-                       if (ret - nr_wake >= nr_requeue)
-                               break;
+               /*
+                * Requeue nr_requeue waiters and possibly one more in the case
+                * of requeue_pi if we couldn't acquire the lock atomically.
+                */
+               if (requeue_pi) {
+                       /* Prepare the waiter to take the rt_mutex. */
+                       atomic_inc(&pi_state->refcount);
+                       this->pi_state = pi_state;
+                       ret = rt_mutex_start_proxy_lock(&pi_state->pi_mutex,
+                                                       this->rt_waiter,
+                                                       this->task, 1);
+                       if (ret == 1) {
+                               /* We got the lock. */
+                               requeue_pi_wake_futex(this, &key2);
+                               continue;
+                       } else if (ret) {
+                               /* -EDEADLK */
+                               this->pi_state = NULL;
+                               free_pi_state(pi_state);
+                               goto out_unlock;
+                       }
                }
+               requeue_futex(this, hb1, hb2, &key2);
+               drop_count++;
        }
 
 out_unlock:
@@ -899,7 +1284,9 @@ out_put_keys:
 out_put_key1:
        put_futex_key(fshared, &key1);
 out:
-       return ret;
+       if (pi_state != NULL)
+               free_pi_state(pi_state);
+       return ret ? ret : task_count;
 }
 
 /* The key must be already stored in q->key. */
@@ -907,8 +1294,6 @@ static inline struct futex_hash_bucket *queue_lock(struct futex_q *q)
 {
        struct futex_hash_bucket *hb;
 
-       init_waitqueue_head(&q->waiter);
-
        get_futex_key_refs(&q->key);
        hb = hash_futex(&q->key);
        q->lock_ptr = &hb->lock;
@@ -1119,39 +1504,153 @@ handle_fault:
  */
 #define FLAGS_SHARED           0x01
 #define FLAGS_CLOCKRT          0x02
+#define FLAGS_HAS_TIMEOUT      0x04
 
 static long futex_wait_restart(struct restart_block *restart);
 
-static int futex_wait(u32 __user *uaddr, int fshared,
-                     u32 val, ktime_t *abs_time, u32 bitset, int clockrt)
+/**
+ * fixup_owner() - Post lock pi_state and corner case management
+ * @uaddr:     user address of the futex
+ * @fshared:   whether the futex is shared (1) or not (0)
+ * @q:         futex_q (contains pi_state and access to the rt_mutex)
+ * @locked:    if the attempt to take the rt_mutex succeeded (1) or not (0)
+ *
+ * After attempting to lock an rt_mutex, this function is called to cleanup
+ * the pi_state owner as well as handle race conditions that may allow us to
+ * acquire the lock. Must be called with the hb lock held.
+ *
+ * Returns:
+ *  1 - success, lock taken
+ *  0 - success, lock not taken
+ * <0 - on error (-EFAULT)
+ */
+static int fixup_owner(u32 __user *uaddr, int fshared, struct futex_q *q,
+                      int locked)
 {
-       struct task_struct *curr = current;
-       struct restart_block *restart;
-       DECLARE_WAITQUEUE(wait, curr);
-       struct futex_hash_bucket *hb;
-       struct futex_q q;
-       u32 uval;
-       int ret;
-       struct hrtimer_sleeper t;
-       int rem = 0;
-
-       if (!bitset)
-               return -EINVAL;
+       struct task_struct *owner;
+       int ret = 0;
 
-       q.pi_state = NULL;
-       q.bitset = bitset;
-retry:
-       q.key = FUTEX_KEY_INIT;
-       ret = get_futex_key(uaddr, fshared, &q.key, VERIFY_READ);
-       if (unlikely(ret != 0))
+       if (locked) {
+               /*
+                * Got the lock. We might not be the anticipated owner if we
+                * did a lock-steal - fix up the PI-state in that case:
+                */
+               if (q->pi_state->owner != current)
+                       ret = fixup_pi_state_owner(uaddr, q, current, fshared);
                goto out;
+       }
 
-retry_private:
-       hb = queue_lock(&q);
+       /*
+        * Catch the rare case, where the lock was released when we were on the
+        * way back before we locked the hash bucket.
+        */
+       if (q->pi_state->owner == current) {
+               /*
+                * Try to get the rt_mutex now. This might fail as some other
+                * task acquired the rt_mutex after we removed ourself from the
+                * rt_mutex waiters list.
+                */
+               if (rt_mutex_trylock(&q->pi_state->pi_mutex)) {
+                       locked = 1;
+                       goto out;
+               }
+
+               /*
+                * pi_state is incorrect, some other task did a lock steal and
+                * we returned due to timeout or signal without taking the
+                * rt_mutex. Too late. We can access the rt_mutex_owner without
+                * locking, as the other task is now blocked on the hash bucket
+                * lock. Fix the state up.
+                */
+               owner = rt_mutex_owner(&q->pi_state->pi_mutex);
+               ret = fixup_pi_state_owner(uaddr, q, owner, fshared);
+               goto out;
+       }
 
        /*
-        * Access the page AFTER the hash-bucket is locked.
-        * Order is important:
+        * Paranoia check. If we did not take the lock, then we should not be
+        * the owner, nor the pending owner, of the rt_mutex.
+        */
+       if (rt_mutex_owner(&q->pi_state->pi_mutex) == current)
+               printk(KERN_ERR "fixup_owner: ret = %d pi-mutex: %p "
+                               "pi-state %p\n", ret,
+                               q->pi_state->pi_mutex.owner,
+                               q->pi_state->owner);
+
+out:
+       return ret ? ret : locked;
+}
+
+/**
+ * futex_wait_queue_me() - queue_me() and wait for wakeup, timeout, or signal
+ * @hb:                the futex hash bucket, must be locked by the caller
+ * @q:         the futex_q to queue up on
+ * @timeout:   the prepared hrtimer_sleeper, or null for no timeout
+ */
+static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
+                               struct hrtimer_sleeper *timeout)
+{
+       queue_me(q, hb);
+
+       /*
+        * There might have been scheduling since the queue_me(), as we
+        * cannot hold a spinlock across the get_user() in case it
+        * faults, and we cannot just set TASK_INTERRUPTIBLE state when
+        * queueing ourselves into the futex hash. This code thus has to
+        * rely on the futex_wake() code removing us from hash when it
+        * wakes us up.
+        */
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       /* Arm the timer */
+       if (timeout) {
+               hrtimer_start_expires(&timeout->timer, HRTIMER_MODE_ABS);
+               if (!hrtimer_active(&timeout->timer))
+                       timeout->task = NULL;
+       }
+
+       /*
+        * !plist_node_empty() is safe here without any lock.
+        * q.lock_ptr != 0 is not safe, because of ordering against wakeup.
+        */
+       if (likely(!plist_node_empty(&q->list))) {
+               /*
+                * If the timer has already expired, current will already be
+                * flagged for rescheduling. Only call schedule if there
+                * is no timeout, or if it has yet to expire.
+                */
+               if (!timeout || timeout->task)
+                       schedule();
+       }
+       __set_current_state(TASK_RUNNING);
+}
+
+/**
+ * futex_wait_setup() - Prepare to wait on a futex
+ * @uaddr:     the futex userspace address
+ * @val:       the expected value
+ * @fshared:   whether the futex is shared (1) or not (0)
+ * @q:         the associated futex_q
+ * @hb:                storage for hash_bucket pointer to be returned to caller
+ *
+ * Setup the futex_q and locate the hash_bucket.  Get the futex value and
+ * compare it with the expected value.  Handle atomic faults internally.
+ * Return with the hb lock held and a q.key reference on success, and unlocked
+ * with no q.key reference on failure.
+ *
+ * Returns:
+ *  0 - uaddr contains val and hb has been locked
+ * <1 - -EFAULT or -EWOULDBLOCK (uaddr does not contain val) and hb is unlcoked
+ */
+static int futex_wait_setup(u32 __user *uaddr, u32 val, int fshared,
+                          struct futex_q *q, struct futex_hash_bucket **hb)
+{
+       u32 uval;
+       int ret;
+
+       /*
+        * Access the page AFTER the hash-bucket is locked.
+        * Order is important:
         *
         *   Userspace waiter: val = var; if (cond(val)) futex_wait(&var, val);
         *   Userspace waker:  if (cond(var)) { var = new; futex_wake(&var); }
@@ -1165,95 +1664,83 @@ retry_private:
         * A consequence is that futex_wait() can return zero and absorb
         * a wakeup when *uaddr != val on entry to the syscall.  This is
         * rare, but normal.
-        *
-        * For shared futexes, we hold the mmap semaphore, so the mapping
-        * cannot have changed since we looked it up in get_futex_key.
         */
+retry:
+       q->key = FUTEX_KEY_INIT;
+       ret = get_futex_key(uaddr, fshared, &q->key, VERIFY_READ);
+       if (unlikely(ret != 0))
+               return ret;
+
+retry_private:
+       *hb = queue_lock(q);
+
        ret = get_futex_value_locked(&uval, uaddr);
 
-       if (unlikely(ret)) {
-               queue_unlock(&q, hb);
+       if (ret) {
+               queue_unlock(q, *hb);
 
                ret = get_user(uval, uaddr);
                if (ret)
-                       goto out_put_key;
+                       goto out;
 
                if (!fshared)
                        goto retry_private;
 
-               put_futex_key(fshared, &q.key);
+               put_futex_key(fshared, &q->key);
                goto retry;
        }
-       ret = -EWOULDBLOCK;
-       if (unlikely(uval != val)) {
-               queue_unlock(&q, hb);
-               goto out_put_key;
-       }
 
-       /* Only actually queue if *uaddr contained val.  */
-       queue_me(&q, hb);
+       if (uval != val) {
+               queue_unlock(q, *hb);
+               ret = -EWOULDBLOCK;
+       }
 
-       /*
-        * There might have been scheduling since the queue_me(), as we
-        * cannot hold a spinlock across the get_user() in case it
-        * faults, and we cannot just set TASK_INTERRUPTIBLE state when
-        * queueing ourselves into the futex hash.  This code thus has to
-        * rely on the futex_wake() code removing us from hash when it
-        * wakes us up.
-        */
+out:
+       if (ret)
+               put_futex_key(fshared, &q->key);
+       return ret;
+}
 
-       /* add_wait_queue is the barrier after __set_current_state. */
-       __set_current_state(TASK_INTERRUPTIBLE);
-       add_wait_queue(&q.waiter, &wait);
-       /*
-        * !plist_node_empty() is safe here without any lock.
-        * q.lock_ptr != 0 is not safe, because of ordering against wakeup.
-        */
-       if (likely(!plist_node_empty(&q.list))) {
-               if (!abs_time)
-                       schedule();
-               else {
-                       hrtimer_init_on_stack(&t.timer,
-                                             clockrt ? CLOCK_REALTIME :
-                                             CLOCK_MONOTONIC,
-                                             HRTIMER_MODE_ABS);
-                       hrtimer_init_sleeper(&t, current);
-                       hrtimer_set_expires_range_ns(&t.timer, *abs_time,
-                                                    current->timer_slack_ns);
-
-                       hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS);
-                       if (!hrtimer_active(&t.timer))
-                               t.task = NULL;
+static int futex_wait(u32 __user *uaddr, int fshared,
+                     u32 val, ktime_t *abs_time, u32 bitset, int clockrt)
+{
+       struct hrtimer_sleeper timeout, *to = NULL;
+       struct restart_block *restart;
+       struct futex_hash_bucket *hb;
+       struct futex_q q;
+       int ret;
 
-                       /*
-                        * the timer could have already expired, in which
-                        * case current would be flagged for rescheduling.
-                        * Don't bother calling schedule.
-                        */
-                       if (likely(t.task))
-                               schedule();
+       if (!bitset)
+               return -EINVAL;
 
-                       hrtimer_cancel(&t.timer);
+       q.pi_state = NULL;
+       q.bitset = bitset;
+       q.rt_waiter = NULL;
 
-                       /* Flag if a timeout occured */
-                       rem = (t.task == NULL);
+       if (abs_time) {
+               to = &timeout;
 
-                       destroy_hrtimer_on_stack(&t.timer);
-               }
+               hrtimer_init_on_stack(&to->timer, clockrt ? CLOCK_REALTIME :
+                                     CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+               hrtimer_init_sleeper(to, current);
+               hrtimer_set_expires_range_ns(&to->timer, *abs_time,
+                                            current->timer_slack_ns);
        }
-       __set_current_state(TASK_RUNNING);
 
-       /*
-        * NOTE: we don't remove ourselves from the waitqueue because
-        * we are the only user of it.
-        */
+       /* Prepare to wait on uaddr. */
+       ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
+       if (ret)
+               goto out;
+
+       /* queue_me and wait for wakeup, timeout, or a signal. */
+       futex_wait_queue_me(hb, &q, to);
 
        /* If we were woken (and unqueued), we succeeded, whatever. */
        ret = 0;
        if (!unqueue_me(&q))
                goto out_put_key;
        ret = -ETIMEDOUT;
-       if (rem)
+       if (to && !to->task)
                goto out_put_key;
 
        /*
@@ -1270,7 +1757,7 @@ retry_private:
        restart->futex.val = val;
        restart->futex.time = abs_time->tv64;
        restart->futex.bitset = bitset;
-       restart->futex.flags = 0;
+       restart->futex.flags = FLAGS_HAS_TIMEOUT;
 
        if (fshared)
                restart->futex.flags |= FLAGS_SHARED;
@@ -1282,6 +1769,10 @@ retry_private:
 out_put_key:
        put_futex_key(fshared, &q.key);
 out:
+       if (to) {
+               hrtimer_cancel(&to->timer);
+               destroy_hrtimer_on_stack(&to->timer);
+       }
        return ret;
 }
 
@@ -1290,13 +1781,16 @@ static long futex_wait_restart(struct restart_block *restart)
 {
        u32 __user *uaddr = (u32 __user *)restart->futex.uaddr;
        int fshared = 0;
-       ktime_t t;
+       ktime_t t, *tp = NULL;
 
-       t.tv64 = restart->futex.time;
+       if (restart->futex.flags & FLAGS_HAS_TIMEOUT) {
+               t.tv64 = restart->futex.time;
+               tp = &t;
+       }
        restart->fn = do_no_restart_syscall;
        if (restart->futex.flags & FLAGS_SHARED)
                fshared = 1;
-       return (long)futex_wait(uaddr, fshared, restart->futex.val, &t,
+       return (long)futex_wait(uaddr, fshared, restart->futex.val, tp,
                                restart->futex.bitset,
                                restart->futex.flags & FLAGS_CLOCKRT);
 }
@@ -1312,11 +1806,10 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
                         int detect, ktime_t *time, int trylock)
 {
        struct hrtimer_sleeper timeout, *to = NULL;
-       struct task_struct *curr = current;
        struct futex_hash_bucket *hb;
-       u32 uval, newval, curval;
+       u32 uval;
        struct futex_q q;
-       int ret, lock_taken, ownerdied = 0;
+       int res, ret;
 
        if (refill_pi_state_cache())
                return -ENOMEM;
@@ -1330,6 +1823,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
        }
 
        q.pi_state = NULL;
+       q.rt_waiter = NULL;
 retry:
        q.key = FUTEX_KEY_INIT;
        ret = get_futex_key(uaddr, fshared, &q.key, VERIFY_WRITE);
@@ -1339,81 +1833,15 @@ retry:
 retry_private:
        hb = queue_lock(&q);
 
-retry_locked:
-       ret = lock_taken = 0;
-
-       /*
-        * To avoid races, we attempt to take the lock here again
-        * (by doing a 0 -> TID atomic cmpxchg), while holding all
-        * the locks. It will most likely not succeed.
-        */
-       newval = task_pid_vnr(current);
-
-       curval = cmpxchg_futex_value_locked(uaddr, 0, newval);
-
-       if (unlikely(curval == -EFAULT))
-               goto uaddr_faulted;
-
-       /*
-        * Detect deadlocks. In case of REQUEUE_PI this is a valid
-        * situation and we return success to user space.
-        */
-       if (unlikely((curval & FUTEX_TID_MASK) == task_pid_vnr(current))) {
-               ret = -EDEADLK;
-               goto out_unlock_put_key;
-       }
-
-       /*
-        * Surprise - we got the lock. Just return to userspace:
-        */
-       if (unlikely(!curval))
-               goto out_unlock_put_key;
-
-       uval = curval;
-
-       /*
-        * Set the WAITERS flag, so the owner will know it has someone
-        * to wake at next unlock
-        */
-       newval = curval | FUTEX_WAITERS;
-
-       /*
-        * There are two cases, where a futex might have no owner (the
-        * owner TID is 0): OWNER_DIED. We take over the futex in this
-        * case. We also do an unconditional take over, when the owner
-        * of the futex died.
-        *
-        * This is safe as we are protected by the hash bucket lock !
-        */
-       if (unlikely(ownerdied || !(curval & FUTEX_TID_MASK))) {
-               /* Keep the OWNER_DIED bit */
-               newval = (curval & ~FUTEX_TID_MASK) | task_pid_vnr(current);
-               ownerdied = 0;
-               lock_taken = 1;
-       }
-
-       curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
-       if (unlikely(curval == -EFAULT))
-               goto uaddr_faulted;
-       if (unlikely(curval != uval))
-               goto retry_locked;
-
-       /*
-        * We took the lock due to owner died take over.
-        */
-       if (unlikely(lock_taken))
-               goto out_unlock_put_key;
-
-       /*
-        * We dont have the lock. Look up the PI state (or create it if
-        * we are the first waiter):
-        */
-       ret = lookup_pi_state(uval, hb, &q.key, &q.pi_state);
-
+       ret = futex_lock_pi_atomic(uaddr, hb, &q.key, &q.pi_state, current, 0);
        if (unlikely(ret)) {
                switch (ret) {
-
+               case 1:
+                       /* We got the lock. */
+                       ret = 0;
+                       goto out_unlock_put_key;
+               case -EFAULT:
+                       goto uaddr_faulted;
                case -EAGAIN:
                        /*
                         * Task is exiting and we just wait for the
@@ -1423,25 +1851,6 @@ retry_locked:
                        put_futex_key(fshared, &q.key);
                        cond_resched();
                        goto retry;
-
-               case -ESRCH:
-                       /*
-                        * No owner found for this futex. Check if the
-                        * OWNER_DIED bit is set to figure out whether
-                        * this is a robust futex or not.
-                        */
-                       if (get_futex_value_locked(&curval, uaddr))
-                               goto uaddr_faulted;
-
-                       /*
-                        * We simply start over in case of a robust
-                        * futex. The code above will take the futex
-                        * and return happy.
-                        */
-                       if (curval & FUTEX_OWNER_DIED) {
-                               ownerdied = 1;
-                               goto retry_locked;
-                       }
                default:
                        goto out_unlock_put_key;
                }
@@ -1465,71 +1874,21 @@ retry_locked:
        }
 
        spin_lock(q.lock_ptr);
-
-       if (!ret) {
-               /*
-                * Got the lock. We might not be the anticipated owner
-                * if we did a lock-steal - fix up the PI-state in
-                * that case:
-                */
-               if (q.pi_state->owner != curr)
-                       ret = fixup_pi_state_owner(uaddr, &q, curr, fshared);
-       } else {
-               /*
-                * Catch the rare case, where the lock was released
-                * when we were on the way back before we locked the
-                * hash bucket.
-                */
-               if (q.pi_state->owner == curr) {
-                       /*
-                        * Try to get the rt_mutex now. This might
-                        * fail as some other task acquired the
-                        * rt_mutex after we removed ourself from the
-                        * rt_mutex waiters list.
-                        */
-                       if (rt_mutex_trylock(&q.pi_state->pi_mutex))
-                               ret = 0;
-                       else {
-                               /*
-                                * pi_state is incorrect, some other
-                                * task did a lock steal and we
-                                * returned due to timeout or signal
-                                * without taking the rt_mutex. Too
-                                * late. We can access the
-                                * rt_mutex_owner without locking, as
-                                * the other task is now blocked on
-                                * the hash bucket lock. Fix the state
-                                * up.
-                                */
-                               struct task_struct *owner;
-                               int res;
-
-                               owner = rt_mutex_owner(&q.pi_state->pi_mutex);
-                               res = fixup_pi_state_owner(uaddr, &q, owner,
-                                                          fshared);
-
-                               /* propagate -EFAULT, if the fixup failed */
-                               if (res)
-                                       ret = res;
-                       }
-               } else {
-                       /*
-                        * Paranoia check. If we did not take the lock
-                        * in the trylock above, then we should not be
-                        * the owner of the rtmutex, neither the real
-                        * nor the pending one:
-                        */
-                       if (rt_mutex_owner(&q.pi_state->pi_mutex) == curr)
-                               printk(KERN_ERR "futex_lock_pi: ret = %d "
-                                      "pi-mutex: %p pi-state %p\n", ret,
-                                      q.pi_state->pi_mutex.owner,
-                                      q.pi_state->owner);
-               }
-       }
+       /*
+        * Fixup the pi_state owner and possibly acquire the lock if we
+        * haven't already.
+        */
+       res = fixup_owner(uaddr, fshared, &q, !ret);
+       /*
+        * If fixup_owner() returned an error, proprogate that.  If it acquired
+        * the lock, clear our -ETIMEDOUT or -EINTR.
+        */
+       if (res)
+               ret = (res < 0) ? res : 0;
 
        /*
-        * If fixup_pi_state_owner() faulted and was unable to handle the
-        * fault, unlock it and return the fault to userspace.
+        * If fixup_owner() faulted and was unable to handle the fault, unlock
+        * it and return the fault to userspace.
         */
        if (ret && (rt_mutex_owner(&q.pi_state->pi_mutex) == current))
                rt_mutex_unlock(&q.pi_state->pi_mutex);
@@ -1537,9 +1896,7 @@ retry_locked:
        /* Unqueue and drop the lock */
        unqueue_me_pi(&q);
 
-       if (to)
-               destroy_hrtimer_on_stack(&to->timer);
-       return ret != -EINTR ? ret : -ERESTARTNOINTR;
+       goto out;
 
 out_unlock_put_key:
        queue_unlock(&q, hb);
@@ -1549,7 +1906,7 @@ out_put_key:
 out:
        if (to)
                destroy_hrtimer_on_stack(&to->timer);
-       return ret;
+       return ret != -EINTR ? ret : -ERESTARTNOINTR;
 
 uaddr_faulted:
        /*
@@ -1572,7 +1929,6 @@ uaddr_faulted:
        goto retry;
 }
 
-
 /*
  * Userspace attempted a TID -> 0 atomic transition, and failed.
  * This is the in-kernel slowpath: we look up the PI state (if any),
@@ -1674,6 +2030,229 @@ pi_faulted:
        return ret;
 }
 
+/**
+ * handle_early_requeue_pi_wakeup() - Detect early wakeup on the initial futex
+ * @hb:                the hash_bucket futex_q was original enqueued on
+ * @q:         the futex_q woken while waiting to be requeued
+ * @key2:      the futex_key of the requeue target futex
+ * @timeout:   the timeout associated with the wait (NULL if none)
+ *
+ * Detect if the task was woken on the initial futex as opposed to the requeue
+ * target futex.  If so, determine if it was a timeout or a signal that caused
+ * the wakeup and return the appropriate error code to the caller.  Must be
+ * called with the hb lock held.
+ *
+ * Returns
+ *  0 - no early wakeup detected
+ * <0 - -ETIMEDOUT or -ERESTARTNOINTR
+ */
+static inline
+int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
+                                  struct futex_q *q, union futex_key *key2,
+                                  struct hrtimer_sleeper *timeout)
+{
+       int ret = 0;
+
+       /*
+        * With the hb lock held, we avoid races while we process the wakeup.
+        * We only need to hold hb (and not hb2) to ensure atomicity as the
+        * wakeup code can't change q.key from uaddr to uaddr2 if we hold hb.
+        * It can't be requeued from uaddr2 to something else since we don't
+        * support a PI aware source futex for requeue.
+        */
+       if (!match_futex(&q->key, key2)) {
+               WARN_ON(q->lock_ptr && (&hb->lock != q->lock_ptr));
+               /*
+                * We were woken prior to requeue by a timeout or a signal.
+                * Unqueue the futex_q and determine which it was.
+                */
+               plist_del(&q->list, &q->list.plist);
+               drop_futex_key_refs(&q->key);
+
+               if (timeout && !timeout->task)
+                       ret = -ETIMEDOUT;
+               else
+                       ret = -ERESTARTNOINTR;
+       }
+       return ret;
+}
+
+/**
+ * futex_wait_requeue_pi() - Wait on uaddr and take uaddr2
+ * @uaddr:     the futex we initialyl wait on (non-pi)
+ * @fshared:   whether the futexes are shared (1) or not (0).  They must be
+ *             the same type, no requeueing from private to shared, etc.
+ * @val:       the expected value of uaddr
+ * @abs_time:  absolute timeout
+ * @bitset:    32 bit wakeup bitset set by userspace, defaults to all.
+ * @clockrt:   whether to use CLOCK_REALTIME (1) or CLOCK_MONOTONIC (0)
+ * @uaddr2:    the pi futex we will take prior to returning to user-space
+ *
+ * The caller will wait on uaddr and will be requeued by futex_requeue() to
+ * uaddr2 which must be PI aware.  Normal wakeup will wake on uaddr2 and
+ * complete the acquisition of the rt_mutex prior to returning to userspace.
+ * This ensures the rt_mutex maintains an owner when it has waiters; without
+ * one, the pi logic wouldn't know which task to boost/deboost, if there was a
+ * need to.
+ *
+ * We call schedule in futex_wait_queue_me() when we enqueue and return there
+ * via the following:
+ * 1) wakeup on uaddr2 after an atomic lock acquisition by futex_requeue()
+ * 2) wakeup on uaddr2 after a requeue and subsequent unlock
+ * 3) signal (before or after requeue)
+ * 4) timeout (before or after requeue)
+ *
+ * If 3, we setup a restart_block with futex_wait_requeue_pi() as the function.
+ *
+ * If 2, we may then block on trying to take the rt_mutex and return via:
+ * 5) successful lock
+ * 6) signal
+ * 7) timeout
+ * 8) other lock acquisition failure
+ *
+ * If 6, we setup a restart_block with futex_lock_pi() as the function.
+ *
+ * If 4 or 7, we cleanup and return with -ETIMEDOUT.
+ *
+ * Returns:
+ *  0 - On success
+ * <0 - On error
+ */
+static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
+                                u32 val, ktime_t *abs_time, u32 bitset,
+                                int clockrt, u32 __user *uaddr2)
+{
+       struct hrtimer_sleeper timeout, *to = NULL;
+       struct rt_mutex_waiter rt_waiter;
+       struct rt_mutex *pi_mutex = NULL;
+       struct futex_hash_bucket *hb;
+       union futex_key key2;
+       struct futex_q q;
+       int res, ret;
+
+       if (!bitset)
+               return -EINVAL;
+
+       if (abs_time) {
+               to = &timeout;
+               hrtimer_init_on_stack(&to->timer, clockrt ? CLOCK_REALTIME :
+                                     CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+               hrtimer_init_sleeper(to, current);
+               hrtimer_set_expires_range_ns(&to->timer, *abs_time,
+                                            current->timer_slack_ns);
+       }
+
+       /*
+        * The waiter is allocated on our stack, manipulated by the requeue
+        * code while we sleep on uaddr.
+        */
+       debug_rt_mutex_init_waiter(&rt_waiter);
+       rt_waiter.task = NULL;
+
+       q.pi_state = NULL;
+       q.bitset = bitset;
+       q.rt_waiter = &rt_waiter;
+
+       key2 = FUTEX_KEY_INIT;
+       ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE);
+       if (unlikely(ret != 0))
+               goto out;
+
+       /* Prepare to wait on uaddr. */
+       ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
+       if (ret)
+               goto out_key2;
+
+       /* Queue the futex_q, drop the hb lock, wait for wakeup. */
+       futex_wait_queue_me(hb, &q, to);
+
+       spin_lock(&hb->lock);
+       ret = handle_early_requeue_pi_wakeup(hb, &q, &key2, to);
+       spin_unlock(&hb->lock);
+       if (ret)
+               goto out_put_keys;
+
+       /*
+        * In order for us to be here, we know our q.key == key2, and since
+        * we took the hb->lock above, we also know that futex_requeue() has
+        * completed and we no longer have to concern ourselves with a wakeup
+        * race with the atomic proxy lock acquition by the requeue code.
+        */
+
+       /* Check if the requeue code acquired the second futex for us. */
+       if (!q.rt_waiter) {
+               /*
+                * Got the lock. We might not be the anticipated owner if we
+                * did a lock-steal - fix up the PI-state in that case.
+                */
+               if (q.pi_state && (q.pi_state->owner != current)) {
+                       spin_lock(q.lock_ptr);
+                       ret = fixup_pi_state_owner(uaddr2, &q, current,
+                                                  fshared);
+                       spin_unlock(q.lock_ptr);
+               }
+       } else {
+               /*
+                * We have been woken up by futex_unlock_pi(), a timeout, or a
+                * signal.  futex_unlock_pi() will not destroy the lock_ptr nor
+                * the pi_state.
+                */
+               WARN_ON(!&q.pi_state);
+               pi_mutex = &q.pi_state->pi_mutex;
+               ret = rt_mutex_finish_proxy_lock(pi_mutex, to, &rt_waiter, 1);
+               debug_rt_mutex_free_waiter(&rt_waiter);
+
+               spin_lock(q.lock_ptr);
+               /*
+                * Fixup the pi_state owner and possibly acquire the lock if we
+                * haven't already.
+                */
+               res = fixup_owner(uaddr2, fshared, &q, !ret);
+               /*
+                * If fixup_owner() returned an error, proprogate that.  If it
+                * acquired the lock, clear our -ETIMEDOUT or -EINTR.
+                */
+               if (res)
+                       ret = (res < 0) ? res : 0;
+
+               /* Unqueue and drop the lock. */
+               unqueue_me_pi(&q);
+       }
+
+       /*
+        * If fixup_pi_state_owner() faulted and was unable to handle the
+        * fault, unlock the rt_mutex and return the fault to userspace.
+        */
+       if (ret == -EFAULT) {
+               if (rt_mutex_owner(pi_mutex) == current)
+                       rt_mutex_unlock(pi_mutex);
+       } else if (ret == -EINTR) {
+               /*
+                * We've already been requeued, but we have no way to
+                * restart by calling futex_lock_pi() directly. We
+                * could restart the syscall, but that will look at
+                * the user space value and return right away. So we
+                * drop back with EWOULDBLOCK to tell user space that
+                * "val" has been changed. That's the same what the
+                * restart of the syscall would do in
+                * futex_wait_setup().
+                */
+               ret = -EWOULDBLOCK;
+       }
+
+out_put_keys:
+       put_futex_key(fshared, &q.key);
+out_key2:
+       put_futex_key(fshared, &key2);
+
+out:
+       if (to) {
+               hrtimer_cancel(&to->timer);
+               destroy_hrtimer_on_stack(&to->timer);
+       }
+       return ret;
+}
+
 /*
  * Support for robust futexes: the kernel cleans up held futexes at
  * thread exit time.
@@ -1896,7 +2475,7 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
                fshared = 1;
 
        clockrt = op & FUTEX_CLOCK_REALTIME;
-       if (clockrt && cmd != FUTEX_WAIT_BITSET)
+       if (clockrt && cmd != FUTEX_WAIT_BITSET && cmd != FUTEX_WAIT_REQUEUE_PI)
                return -ENOSYS;
 
        switch (cmd) {
@@ -1911,10 +2490,11 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
                ret = futex_wake(uaddr, fshared, val, val3);
                break;
        case FUTEX_REQUEUE:
-               ret = futex_requeue(uaddr, fshared, uaddr2, val, val2, NULL);
+               ret = futex_requeue(uaddr, fshared, uaddr2, val, val2, NULL, 0);
                break;
        case FUTEX_CMP_REQUEUE:
-               ret = futex_requeue(uaddr, fshared, uaddr2, val, val2, &val3);
+               ret = futex_requeue(uaddr, fshared, uaddr2, val, val2, &val3,
+                                   0);
                break;
        case FUTEX_WAKE_OP:
                ret = futex_wake_op(uaddr, fshared, uaddr2, val, val2, val3);
@@ -1931,6 +2511,15 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
                if (futex_cmpxchg_enabled)
                        ret = futex_lock_pi(uaddr, fshared, 0, timeout, 1);
                break;
+       case FUTEX_WAIT_REQUEUE_PI:
+               val3 = FUTEX_BITSET_MATCH_ANY;
+               ret = futex_wait_requeue_pi(uaddr, fshared, val, timeout, val3,
+                                           clockrt, uaddr2);
+               break;
+       case FUTEX_CMP_REQUEUE_PI:
+               ret = futex_requeue(uaddr, fshared, uaddr2, val, val2, &val3,
+                                   1);
+               break;
        default:
                ret = -ENOSYS;
        }
@@ -1948,7 +2537,8 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
        int cmd = op & FUTEX_CMD_MASK;
 
        if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
-                     cmd == FUTEX_WAIT_BITSET)) {
+                     cmd == FUTEX_WAIT_BITSET ||
+                     cmd == FUTEX_WAIT_REQUEUE_PI)) {
                if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
                        return -EFAULT;
                if (!timespec_valid(&ts))
@@ -1960,11 +2550,11 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
                tp = &t;
        }
        /*
-        * requeue parameter in 'utime' if cmd == FUTEX_REQUEUE.
+        * requeue parameter in 'utime' if cmd == FUTEX_*_REQUEUE_*.
         * number of waiters to wake in 'utime' if cmd == FUTEX_WAKE_OP.
         */
        if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE ||
-           cmd == FUTEX_WAKE_OP)
+           cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)
                val2 = (u32) (unsigned long) utime;
 
        return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
index 3394f8f52964b3d9b4433a3560ff94eb32b20cb8..7d047808419da88e273fba8cd1efd88d9aaa5bcd 100644 (file)
@@ -3,5 +3,5 @@ obj-y := handle.o manage.o spurious.o resend.o chip.o devres.o
 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_NUMA_IRQ_DESC) += numa_migrate.o
 obj-$(CONFIG_PM_SLEEP) += pm.o
index c687ba4363f2b4a95a5c3988998286a1e8ab699b..13c68e71b726c674619633de2f6e200b00adc039 100644 (file)
@@ -359,7 +359,6 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
 
        spin_lock(&desc->lock);
        mask_ack_irq(desc, irq);
-       desc = irq_remap_to_desc(irq, desc);
 
        if (unlikely(desc->status & IRQ_INPROGRESS))
                goto out_unlock;
@@ -438,7 +437,6 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
        desc->status &= ~IRQ_INPROGRESS;
 out:
        desc->chip->eoi(irq);
-       desc = irq_remap_to_desc(irq, desc);
 
        spin_unlock(&desc->lock);
 }
@@ -475,7 +473,6 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
                    !desc->action)) {
                desc->status |= (IRQ_PENDING | IRQ_MASKED);
                mask_ack_irq(desc, irq);
-               desc = irq_remap_to_desc(irq, desc);
                goto out_unlock;
        }
        kstat_incr_irqs_this_cpu(irq, desc);
@@ -483,7 +480,6 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
        /* Start handling the irq */
        if (desc->chip->ack)
                desc->chip->ack(irq);
-       desc = irq_remap_to_desc(irq, desc);
 
        /* Mark the IRQ currently in progress.*/
        desc->status |= IRQ_INPROGRESS;
@@ -544,10 +540,8 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
        if (!noirqdebug)
                note_interrupt(irq, desc, action_ret);
 
-       if (desc->chip->eoi) {
+       if (desc->chip->eoi)
                desc->chip->eoi(irq);
-               desc = irq_remap_to_desc(irq, desc);
-       }
 }
 
 void
@@ -582,10 +576,8 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 
        /* Uninstall? */
        if (handle == handle_bad_irq) {
-               if (desc->chip != &no_irq_chip) {
+               if (desc->chip != &no_irq_chip)
                        mask_ack_irq(desc, irq);
-                       desc = irq_remap_to_desc(irq, desc);
-               }
                desc->status |= IRQ_DISABLED;
                desc->depth = 1;
        }
index 26e08754744fa13dd9da3e919be6adb3976b2b04..a60018402f4228b46d5870ee93f9e86ae417137a 100644 (file)
  */
 
 #include <linux/irq.h>
+#include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/random.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/rculist.h>
 #include <linux/hash.h>
-#include <trace/irq.h>
 #include <linux/bootmem.h>
+#include <trace/events/irq.h>
 
 #include "internals.h"
 
@@ -81,45 +82,48 @@ static struct irq_desc irq_desc_init = {
        .lock       = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
 };
 
-void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr)
+void __ref init_kstat_irqs(struct irq_desc *desc, int node, int nr)
 {
-       int node;
        void *ptr;
 
-       node = cpu_to_node(cpu);
-       ptr = kzalloc_node(nr * sizeof(*desc->kstat_irqs), GFP_ATOMIC, node);
+       if (slab_is_available())
+               ptr = kzalloc_node(nr * sizeof(*desc->kstat_irqs),
+                                  GFP_ATOMIC, node);
+       else
+               ptr = alloc_bootmem_node(NODE_DATA(node),
+                               nr * sizeof(*desc->kstat_irqs));
 
        /*
         * don't overwite if can not get new one
         * init_copy_kstat_irqs() could still use old one
         */
        if (ptr) {
-               printk(KERN_DEBUG "  alloc kstat_irqs on cpu %d node %d\n",
-                        cpu, node);
+               printk(KERN_DEBUG "  alloc kstat_irqs on node %d\n", node);
                desc->kstat_irqs = ptr;
        }
 }
 
-static void init_one_irq_desc(int irq, struct irq_desc *desc, int cpu)
+static void init_one_irq_desc(int irq, struct irq_desc *desc, int node)
 {
        memcpy(desc, &irq_desc_init, sizeof(struct irq_desc));
 
        spin_lock_init(&desc->lock);
        desc->irq = irq;
 #ifdef CONFIG_SMP
-       desc->cpu = cpu;
+       desc->node = node;
 #endif
        lockdep_set_class(&desc->lock, &irq_desc_lock_class);
-       init_kstat_irqs(desc, cpu, nr_cpu_ids);
+       init_kstat_irqs(desc, node, nr_cpu_ids);
        if (!desc->kstat_irqs) {
                printk(KERN_ERR "can not alloc kstat_irqs\n");
                BUG_ON(1);
        }
-       if (!init_alloc_desc_masks(desc, cpu, false)) {
+       if (!alloc_desc_masks(desc, node, false)) {
                printk(KERN_ERR "can not alloc irq_desc cpumasks\n");
                BUG_ON(1);
        }
-       arch_init_chip_data(desc, cpu);
+       init_desc_masks(desc);
+       arch_init_chip_data(desc, node);
 }
 
 /*
@@ -169,7 +173,8 @@ int __init early_irq_init(void)
                desc[i].irq = i;
                desc[i].kstat_irqs = kstat_irqs_legacy + i * nr_cpu_ids;
                lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
-               init_alloc_desc_masks(&desc[i], 0, true);
+               alloc_desc_masks(&desc[i], 0, true);
+               init_desc_masks(&desc[i]);
                irq_desc_ptrs[i] = desc + i;
        }
 
@@ -187,11 +192,10 @@ struct irq_desc *irq_to_desc(unsigned int irq)
        return NULL;
 }
 
-struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu)
+struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node)
 {
        struct irq_desc *desc;
        unsigned long flags;
-       int node;
 
        if (irq >= nr_irqs) {
                WARN(1, "irq (%d) >= nr_irqs (%d) in irq_to_desc_alloc\n",
@@ -210,15 +214,17 @@ struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu)
        if (desc)
                goto out_unlock;
 
-       node = cpu_to_node(cpu);
-       desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node);
-       printk(KERN_DEBUG "  alloc irq_desc for %d on cpu %d node %d\n",
-                irq, cpu, node);
+       if (slab_is_available())
+               desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node);
+       else
+               desc = alloc_bootmem_node(NODE_DATA(node), sizeof(*desc));
+
+       printk(KERN_DEBUG "  alloc irq_desc for %d on node %d\n", irq, node);
        if (!desc) {
                printk(KERN_ERR "can not alloc irq_desc\n");
                BUG_ON(1);
        }
-       init_one_irq_desc(irq, desc, cpu);
+       init_one_irq_desc(irq, desc, node);
 
        irq_desc_ptrs[irq] = desc;
 
@@ -256,7 +262,8 @@ int __init early_irq_init(void)
 
        for (i = 0; i < count; i++) {
                desc[i].irq = i;
-               init_alloc_desc_masks(&desc[i], 0, true);
+               alloc_desc_masks(&desc[i], 0, true);
+               init_desc_masks(&desc[i]);
                desc[i].kstat_irqs = kstat_irqs_all[i];
        }
        return arch_early_irq_init();
@@ -267,7 +274,7 @@ struct irq_desc *irq_to_desc(unsigned int irq)
        return (irq < NR_IRQS) ? irq_desc + irq : NULL;
 }
 
-struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu)
+struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node)
 {
        return irq_to_desc(irq);
 }
@@ -348,9 +355,6 @@ static void warn_no_thread(unsigned int irq, struct irqaction *action)
               "but no thread function available.", irq, action->name);
 }
 
-DEFINE_TRACE(irq_handler_entry);
-DEFINE_TRACE(irq_handler_exit);
-
 /**
  * handle_IRQ_event - irq action chain handler
  * @irq:       the interrupt number
@@ -453,11 +457,8 @@ unsigned int __do_IRQ(unsigned int irq)
                /*
                 * No locking required for CPU-local interrupts:
                 */
-               if (desc->chip->ack) {
+               if (desc->chip->ack)
                        desc->chip->ack(irq);
-                       /* get new one */
-                       desc = irq_remap_to_desc(irq, desc);
-               }
                if (likely(!(desc->status & IRQ_DISABLED))) {
                        action_ret = handle_IRQ_event(irq, desc->action);
                        if (!noirqdebug)
@@ -468,10 +469,8 @@ unsigned int __do_IRQ(unsigned int irq)
        }
 
        spin_lock(&desc->lock);
-       if (desc->chip->ack) {
+       if (desc->chip->ack)
                desc->chip->ack(irq);
-               desc = irq_remap_to_desc(irq, desc);
-       }
        /*
         * REPLAY is when Linux resends an IRQ that was dropped earlier
         * WAITING is used by probe to mark irqs that are being tested
index 01ce20eab38fed96a7b5a861940ba58d47c18fbf..73468253143ba55883072d1020791c11b1e30210 100644 (file)
@@ -16,7 +16,7 @@ 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);
+extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
 extern void clear_kstat_irqs(struct irq_desc *desc);
 extern spinlock_t sparse_irq_lock;
 
@@ -42,6 +42,9 @@ static inline void unregister_handler_proc(unsigned int irq,
 
 extern int irq_select_affinity_usr(unsigned int irq);
 
+extern void
+irq_set_thread_affinity(struct irq_desc *desc, const struct cpumask *cpumask);
+
 /*
  * Debugging printout:
  */
index 2734eca59243bd8b0783b3553622363b2ce8129e..aaf5c9d05770378b42acc2d41905ceb543f1f280 100644 (file)
@@ -80,7 +80,7 @@ int irq_can_set_affinity(unsigned int irq)
        return 1;
 }
 
-static void
+void
 irq_set_thread_affinity(struct irq_desc *desc, const struct cpumask *cpumask)
 {
        struct irqaction *action = desc->action;
@@ -109,17 +109,22 @@ int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)
        spin_lock_irqsave(&desc->lock, flags);
 
 #ifdef CONFIG_GENERIC_PENDING_IRQ
-       if (desc->status & IRQ_MOVE_PCNTXT)
-               desc->chip->set_affinity(irq, cpumask);
+       if (desc->status & IRQ_MOVE_PCNTXT) {
+               if (!desc->chip->set_affinity(irq, cpumask)) {
+                       cpumask_copy(desc->affinity, cpumask);
+                       irq_set_thread_affinity(desc, cpumask);
+               }
+       }
        else {
                desc->status |= IRQ_MOVE_PENDING;
                cpumask_copy(desc->pending_mask, cpumask);
        }
 #else
-       cpumask_copy(desc->affinity, cpumask);
-       desc->chip->set_affinity(irq, cpumask);
+       if (!desc->chip->set_affinity(irq, cpumask)) {
+               cpumask_copy(desc->affinity, cpumask);
+               irq_set_thread_affinity(desc, cpumask);
+       }
 #endif
-       irq_set_thread_affinity(desc, cpumask);
        desc->status |= IRQ_AFFINITY_SET;
        spin_unlock_irqrestore(&desc->lock, flags);
        return 0;
index e05ad9be43b7a5fa7e6d6a24f94e49828a73572a..cfe767ca154501460f9f7e757c08d881611e9c95 100644 (file)
@@ -1,5 +1,8 @@
 
 #include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include "internals.h"
 
 void move_masked_irq(int irq)
 {
@@ -39,11 +42,12 @@ void move_masked_irq(int irq)
         * masking the irqs.
         */
        if (likely(cpumask_any_and(desc->pending_mask, cpu_online_mask)
-                  < nr_cpu_ids)) {
-               cpumask_and(desc->affinity,
-                           desc->pending_mask, cpu_online_mask);
-               desc->chip->set_affinity(irq, desc->affinity);
-       }
+                  < nr_cpu_ids))
+               if (!desc->chip->set_affinity(irq, desc->pending_mask)) {
+                       cpumask_copy(desc->affinity, desc->pending_mask);
+                       irq_set_thread_affinity(desc, desc->pending_mask);
+               }
+
        cpumask_clear(desc->pending_mask);
 }
 
index 44bbdcbaf8d2c8193f2d631b54061047546d0065..2f69bee57bf21ca5a42027834ddccee96670d989 100644 (file)
@@ -15,9 +15,9 @@
 
 static void init_copy_kstat_irqs(struct irq_desc *old_desc,
                                 struct irq_desc *desc,
-                                int cpu, int nr)
+                                int node, int nr)
 {
-       init_kstat_irqs(desc, cpu, nr);
+       init_kstat_irqs(desc, node, nr);
 
        if (desc->kstat_irqs != old_desc->kstat_irqs)
                memcpy(desc->kstat_irqs, old_desc->kstat_irqs,
@@ -34,20 +34,20 @@ static void free_kstat_irqs(struct irq_desc *old_desc, struct irq_desc *desc)
 }
 
 static bool init_copy_one_irq_desc(int irq, struct irq_desc *old_desc,
-                struct irq_desc *desc, int cpu)
+                struct irq_desc *desc, int node)
 {
        memcpy(desc, old_desc, sizeof(struct irq_desc));
-       if (!init_alloc_desc_masks(desc, cpu, false)) {
+       if (!alloc_desc_masks(desc, node, false)) {
                printk(KERN_ERR "irq %d: can not get new irq_desc cpumask "
                                "for migration.\n", irq);
                return false;
        }
        spin_lock_init(&desc->lock);
-       desc->cpu = cpu;
+       desc->node = node;
        lockdep_set_class(&desc->lock, &irq_desc_lock_class);
-       init_copy_kstat_irqs(old_desc, desc, cpu, nr_cpu_ids);
+       init_copy_kstat_irqs(old_desc, desc, node, nr_cpu_ids);
        init_copy_desc_masks(old_desc, desc);
-       arch_init_copy_chip_data(old_desc, desc, cpu);
+       arch_init_copy_chip_data(old_desc, desc, node);
        return true;
 }
 
@@ -59,12 +59,11 @@ static void free_one_irq_desc(struct irq_desc *old_desc, struct irq_desc *desc)
 }
 
 static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc,
-                                               int cpu)
+                                               int node)
 {
        struct irq_desc *desc;
        unsigned int irq;
        unsigned long flags;
-       int node;
 
        irq = old_desc->irq;
 
@@ -76,7 +75,6 @@ static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc,
        if (desc && old_desc != desc)
                goto out_unlock;
 
-       node = cpu_to_node(cpu);
        desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node);
        if (!desc) {
                printk(KERN_ERR "irq %d: can not get new irq_desc "
@@ -85,7 +83,7 @@ static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc,
                desc = old_desc;
                goto out_unlock;
        }
-       if (!init_copy_one_irq_desc(irq, old_desc, desc, cpu)) {
+       if (!init_copy_one_irq_desc(irq, old_desc, desc, node)) {
                /* still use old one */
                kfree(desc);
                desc = old_desc;
@@ -97,9 +95,7 @@ static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc,
 
        /* free the old one */
        free_one_irq_desc(old_desc, desc);
-       spin_unlock(&old_desc->lock);
        kfree(old_desc);
-       spin_lock(&desc->lock);
 
        return desc;
 
@@ -109,24 +105,14 @@ out_unlock:
        return desc;
 }
 
-struct irq_desc *move_irq_desc(struct irq_desc *desc, int cpu)
+struct irq_desc *move_irq_desc(struct irq_desc *desc, int node)
 {
-       int old_cpu;
-       int node, old_node;
-
        /* those all static, do move them */
        if (desc->irq < NR_IRQS_LEGACY)
                return desc;
 
-       old_cpu = desc->cpu;
-       if (old_cpu != cpu) {
-               node = cpu_to_node(cpu);
-               old_node = cpu_to_node(old_cpu);
-               if (old_node != node)
-                       desc = __real_move_irq_desc(desc, cpu);
-               else
-                       desc->cpu = cpu;
-       }
+       if (desc->node != node)
+               desc = __real_move_irq_desc(desc, node);
 
        return desc;
 }
index 4ebaf8519abf64fb0cc4e93ef42d7ad0cf286c9f..41c88fe40500399c76f0382d51a3fb05aef03211 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/file.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
-#include <trace/sched.h>
+#include <trace/events/sched.h>
 
 #define KTHREAD_NICE_LEVEL (-5)
 
@@ -21,9 +21,6 @@ static DEFINE_SPINLOCK(kthread_create_lock);
 static LIST_HEAD(kthread_create_list);
 struct task_struct *kthreadd_task;
 
-DEFINE_TRACE(sched_kthread_stop);
-DEFINE_TRACE(sched_kthread_stop_ret);
-
 struct kthread_create_info
 {
        /* Information passed to kthread() from kthreadd. */
index accb40cdb12a4cd0c3d5fd880c706d986568557d..8bbeef996c76598b7e45e3b48186fc18c03b5be0 100644 (file)
 #include <linux/hash.h>
 #include <linux/ftrace.h>
 #include <linux/stringify.h>
-#include <trace/lockdep.h>
 
 #include <asm/sections.h>
 
 #include "lockdep_internals.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/lockdep.h>
+
 #ifdef CONFIG_PROVE_LOCKING
 int prove_locking = 1;
 module_param(prove_locking, int, 0644);
@@ -2935,8 +2937,6 @@ void lock_set_class(struct lockdep_map *lock, const char *name,
 }
 EXPORT_SYMBOL_GPL(lock_set_class);
 
-DEFINE_TRACE(lock_acquire);
-
 /*
  * We are not always called with irqs disabled - do that here,
  * and also avoid lockdep recursion:
@@ -2963,8 +2963,6 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 }
 EXPORT_SYMBOL_GPL(lock_acquire);
 
-DEFINE_TRACE(lock_release);
-
 void lock_release(struct lockdep_map *lock, int nested,
                          unsigned long ip)
 {
@@ -3105,6 +3103,8 @@ found_it:
                hlock->holdtime_stamp = now;
        }
 
+       trace_lock_acquired(lock, ip, waittime);
+
        stats = get_lock_stats(hlock_class(hlock));
        if (waittime) {
                if (hlock->read)
@@ -3120,8 +3120,6 @@ found_it:
        lock->ip = ip;
 }
 
-DEFINE_TRACE(lock_contended);
-
 void lock_contended(struct lockdep_map *lock, unsigned long ip)
 {
        unsigned long flags;
@@ -3143,14 +3141,10 @@ void lock_contended(struct lockdep_map *lock, unsigned long ip)
 }
 EXPORT_SYMBOL_GPL(lock_contended);
 
-DEFINE_TRACE(lock_acquired);
-
 void lock_acquired(struct lockdep_map *lock, unsigned long ip)
 {
        unsigned long flags;
 
-       trace_lock_acquired(lock, ip);
-
        if (unlikely(!lock_stat))
                return;
 
index e797812a4d95f164bb377447a62de3089c0ba182..278e9b6762bb703c1f2c82809e1ad311db900c76 100644 (file)
@@ -18,6 +18,7 @@
 */
 #include <linux/module.h>
 #include <linux/moduleloader.h>
+#include <linux/ftrace_event.h>
 #include <linux/init.h>
 #include <linux/kallsyms.h>
 #include <linux/fs.h>
@@ -72,6 +73,9 @@ DEFINE_MUTEX(module_mutex);
 EXPORT_SYMBOL_GPL(module_mutex);
 static LIST_HEAD(modules);
 
+/* Block module loading/unloading? */
+int modules_disabled = 0;
+
 /* Waiting for a module to finish initializing? */
 static DECLARE_WAIT_QUEUE_HEAD(module_wq);
 
@@ -777,7 +781,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
        char name[MODULE_NAME_LEN];
        int ret, forced = 0;
 
-       if (!capable(CAP_SYS_MODULE))
+       if (!capable(CAP_SYS_MODULE) || modules_disabled)
                return -EPERM;
 
        if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0)
@@ -1489,9 +1493,6 @@ static void free_module(struct module *mod)
        /* Free any allocated parameters. */
        destroy_params(mod->kp, mod->num_kp);
 
-       /* release any pointers to mcount in this module */
-       ftrace_release(mod->module_core, mod->core_size);
-
        /* This may be NULL, but that's OK */
        module_free(mod, mod->module_init);
        kfree(mod->args);
@@ -1892,11 +1893,9 @@ static noinline struct module *load_module(void __user *umod,
        unsigned int symindex = 0;
        unsigned int strindex = 0;
        unsigned int modindex, versindex, infoindex, pcpuindex;
-       unsigned int num_mcount;
        struct module *mod;
        long err = 0;
        void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
-       unsigned long *mseg;
        mm_segment_t old_fs;
 
        DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
@@ -2172,7 +2171,19 @@ static noinline struct module *load_module(void __user *umod,
                                        sizeof(*mod->tracepoints),
                                        &mod->num_tracepoints);
 #endif
-
+#ifdef CONFIG_EVENT_TRACING
+       mod->trace_events = section_objs(hdr, sechdrs, secstrings,
+                                        "_ftrace_events",
+                                        sizeof(*mod->trace_events),
+                                        &mod->num_trace_events);
+#endif
+#ifdef CONFIG_FTRACE_MCOUNT_RECORD
+       /* sechdrs[0].sh_size is always zero */
+       mod->ftrace_callsites = section_objs(hdr, sechdrs, secstrings,
+                                            "__mcount_loc",
+                                            sizeof(*mod->ftrace_callsites),
+                                            &mod->num_ftrace_callsites);
+#endif
 #ifdef CONFIG_MODVERSIONS
        if ((mod->num_syms && !mod->crcs)
            || (mod->num_gpl_syms && !mod->gpl_crcs)
@@ -2237,11 +2248,6 @@ static noinline struct module *load_module(void __user *umod,
                        dynamic_debug_setup(debug, num_debug);
        }
 
-       /* sechdrs[0].sh_size is always zero */
-       mseg = section_objs(hdr, sechdrs, secstrings, "__mcount_loc",
-                           sizeof(*mseg), &num_mcount);
-       ftrace_init_module(mod, mseg, mseg + num_mcount);
-
        err = module_finalize(hdr, sechdrs, mod);
        if (err < 0)
                goto cleanup;
@@ -2302,7 +2308,6 @@ static noinline struct module *load_module(void __user *umod,
  cleanup:
        kobject_del(&mod->mkobj.kobj);
        kobject_put(&mod->mkobj.kobj);
-       ftrace_release(mod->module_core, mod->core_size);
  free_unload:
        module_unload_free(mod);
 #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
@@ -2336,7 +2341,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
        int ret = 0;
 
        /* Must have permission */
-       if (!capable(CAP_SYS_MODULE))
+       if (!capable(CAP_SYS_MODULE) || modules_disabled)
                return -EPERM;
 
        /* Only one module load at a time, please */
index 507cf2b5e9f1e6328b2e335a3a05c0ead6a0ff3e..e5cc0cd28d541eb64526b4f7d68c9dca29eaa571 100644 (file)
@@ -249,7 +249,9 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
 
                /* didnt get the lock, go to sleep: */
                spin_unlock_mutex(&lock->wait_lock, flags);
-               __schedule();
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
                spin_lock_mutex(&lock->wait_lock, flags);
        }
 
@@ -471,5 +473,28 @@ int __sched mutex_trylock(struct mutex *lock)
 
        return ret;
 }
-
 EXPORT_SYMBOL(mutex_trylock);
+
+/**
+ * atomic_dec_and_mutex_lock - return holding mutex if we dec to 0
+ * @cnt: the atomic which we are to dec
+ * @lock: the mutex to return holding if we dec to 0
+ *
+ * return true and hold lock if we dec to 0, return false otherwise
+ */
+int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock)
+{
+       /* dec if we can't possibly hit 0 */
+       if (atomic_add_unless(cnt, -1, 1))
+               return 0;
+       /* we might hit 0, so take the lock */
+       mutex_lock(lock);
+       if (!atomic_dec_and_test(cnt)) {
+               /* when we actually did the dec, we didn't hit 0 */
+               mutex_unlock(lock);
+               return 0;
+       }
+       /* we hit 0, and we hold the lock */
+       return 1;
+}
+EXPORT_SYMBOL(atomic_dec_and_mutex_lock);
index 42c317874cfa8d2703c13f3c44757a6f397459ac..f6d8b8cb5e34b64e23227314b0ab7400abe28287 100644 (file)
 #include <linux/uaccess.h>
 
 
-/*
- * Initialize a new task whose father had been ptraced.
- *
- * Called from copy_process().
- */
-void ptrace_fork(struct task_struct *child, unsigned long clone_flags)
-{
-       arch_ptrace_fork(child, clone_flags);
-}
-
 /*
  * ptrace a task: make the debugger its new parent and
  * move it to the ptrace list.
@@ -185,10 +175,11 @@ int ptrace_attach(struct task_struct *task)
        if (same_thread_group(task, current))
                goto out;
 
-       /* Protect exec's credential calculations against our interference;
-        * SUID, SGID and LSM creds get determined differently under ptrace.
+       /* Protect the target's credential calculations against our
+        * interference; SUID, SGID and LSM creds get determined differently
+        * under ptrace.
         */
-       retval = mutex_lock_interruptible(&task->cred_exec_mutex);
+       retval = mutex_lock_interruptible(&task->cred_guard_mutex);
        if (retval  < 0)
                goto out;
 
@@ -232,7 +223,7 @@ repeat:
 bad:
        write_unlock_irqrestore(&tasklist_lock, flags);
        task_unlock(task);
-       mutex_unlock(&task->cred_exec_mutex);
+       mutex_unlock(&task->cred_guard_mutex);
 out:
        return retval;
 }
index ce97a4df64d3539edc785ff9db119c3ba3edbe07..beb0e659adcc60be60bcc1efd2c6e9ca45367afe 100644 (file)
@@ -1356,17 +1356,11 @@ static int rcu_sched_grace_period(void *arg)
 
                rcu_ctrlblk.sched_sleep = rcu_sched_sleeping;
                spin_unlock_irqrestore(&rcu_ctrlblk.schedlock, flags);
-               ret = 0;
+               ret = 0; /* unused */
                __wait_event_interruptible(rcu_ctrlblk.sched_wq,
                        rcu_ctrlblk.sched_sleep != rcu_sched_sleeping,
                        ret);
 
-               /*
-                * Signals would prevent us from sleeping, and we cannot
-                * do much with them in any case.  So flush them.
-                */
-               if (ret)
-                       flush_signals(current);
                couldsleepnext = 0;
 
        } while (!kthread_should_stop());
index d2a372fb0b9b511cfe9ebdc1f5431f2ec5faafcd..0dccfbba6d267ad59b62314d665a3a91b3104252 100644 (file)
@@ -1259,31 +1259,44 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp)
        check_cpu_stall(rsp, rdp);
 
        /* Is the RCU core waiting for a quiescent state from this CPU? */
-       if (rdp->qs_pending)
+       if (rdp->qs_pending) {
+               rdp->n_rp_qs_pending++;
                return 1;
+       }
 
        /* Does this CPU have callbacks ready to invoke? */
-       if (cpu_has_callbacks_ready_to_invoke(rdp))
+       if (cpu_has_callbacks_ready_to_invoke(rdp)) {
+               rdp->n_rp_cb_ready++;
                return 1;
+       }
 
        /* Has RCU gone idle with this CPU needing another grace period? */
-       if (cpu_needs_another_gp(rsp, rdp))
+       if (cpu_needs_another_gp(rsp, rdp)) {
+               rdp->n_rp_cpu_needs_gp++;
                return 1;
+       }
 
        /* Has another RCU grace period completed?  */
-       if (ACCESS_ONCE(rsp->completed) != rdp->completed) /* outside of lock */
+       if (ACCESS_ONCE(rsp->completed) != rdp->completed) { /* outside lock */
+               rdp->n_rp_gp_completed++;
                return 1;
+       }
 
        /* Has a new RCU grace period started? */
-       if (ACCESS_ONCE(rsp->gpnum) != rdp->gpnum) /* outside of lock */
+       if (ACCESS_ONCE(rsp->gpnum) != rdp->gpnum) { /* outside lock */
+               rdp->n_rp_gp_started++;
                return 1;
+       }
 
        /* Has an RCU GP gone long enough to send resched IPIs &c? */
        if (ACCESS_ONCE(rsp->completed) != ACCESS_ONCE(rsp->gpnum) &&
-           ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0))
+           ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0)) {
+               rdp->n_rp_need_fqs++;
                return 1;
+       }
 
        /* nothing to do */
+       rdp->n_rp_need_nothing++;
        return 0;
 }
 
index 4b1875ba94044216250d938713ddf76ac2280f1c..fe1dcdbf1ca340558191a02ee408fea17e04fadd 100644 (file)
@@ -213,7 +213,63 @@ static struct file_operations rcugp_fops = {
        .release = single_release,
 };
 
-static struct dentry *rcudir, *datadir, *datadir_csv, *hierdir, *gpdir;
+static void print_one_rcu_pending(struct seq_file *m, struct rcu_data *rdp)
+{
+       seq_printf(m, "%3d%cnp=%ld "
+                  "qsp=%ld cbr=%ld cng=%ld gpc=%ld gps=%ld nf=%ld nn=%ld\n",
+                  rdp->cpu,
+                  cpu_is_offline(rdp->cpu) ? '!' : ' ',
+                  rdp->n_rcu_pending,
+                  rdp->n_rp_qs_pending,
+                  rdp->n_rp_cb_ready,
+                  rdp->n_rp_cpu_needs_gp,
+                  rdp->n_rp_gp_completed,
+                  rdp->n_rp_gp_started,
+                  rdp->n_rp_need_fqs,
+                  rdp->n_rp_need_nothing);
+}
+
+static void print_rcu_pendings(struct seq_file *m, struct rcu_state *rsp)
+{
+       int cpu;
+       struct rcu_data *rdp;
+
+       for_each_possible_cpu(cpu) {
+               rdp = rsp->rda[cpu];
+               if (rdp->beenonline)
+                       print_one_rcu_pending(m, rdp);
+       }
+}
+
+static int show_rcu_pending(struct seq_file *m, void *unused)
+{
+       seq_puts(m, "rcu:\n");
+       print_rcu_pendings(m, &rcu_state);
+       seq_puts(m, "rcu_bh:\n");
+       print_rcu_pendings(m, &rcu_bh_state);
+       return 0;
+}
+
+static int rcu_pending_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, show_rcu_pending, NULL);
+}
+
+static struct file_operations rcu_pending_fops = {
+       .owner = THIS_MODULE,
+       .open = rcu_pending_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static struct dentry *rcudir;
+static struct dentry *datadir;
+static struct dentry *datadir_csv;
+static struct dentry *gpdir;
+static struct dentry *hierdir;
+static struct dentry *rcu_pendingdir;
+
 static int __init rcuclassic_trace_init(void)
 {
        rcudir = debugfs_create_dir("rcu", NULL);
@@ -238,6 +294,11 @@ static int __init rcuclassic_trace_init(void)
                                                NULL, &rcuhier_fops);
        if (!hierdir)
                goto free_out;
+
+       rcu_pendingdir = debugfs_create_file("rcu_pending", 0444, rcudir,
+                                               NULL, &rcu_pending_fops);
+       if (!rcu_pendingdir)
+               goto free_out;
        return 0;
 free_out:
        if (datadir)
@@ -257,6 +318,7 @@ static void __exit rcuclassic_trace_cleanup(void)
        debugfs_remove(datadir_csv);
        debugfs_remove(gpdir);
        debugfs_remove(hierdir);
+       debugfs_remove(rcu_pendingdir);
        debugfs_remove(rcudir);
 }
 
index 69d9cb921ffa657ef6939be6dcfb053570fb019f..820c5af44f3ec6472db64bf32daeccba458ab7d7 100644 (file)
@@ -300,7 +300,8 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
  * assigned pending owner [which might not have taken the
  * lock yet]:
  */
-static inline int try_to_steal_lock(struct rt_mutex *lock)
+static inline int try_to_steal_lock(struct rt_mutex *lock,
+                                   struct task_struct *task)
 {
        struct task_struct *pendowner = rt_mutex_owner(lock);
        struct rt_mutex_waiter *next;
@@ -309,11 +310,11 @@ static inline int try_to_steal_lock(struct rt_mutex *lock)
        if (!rt_mutex_owner_pending(lock))
                return 0;
 
-       if (pendowner == current)
+       if (pendowner == task)
                return 1;
 
        spin_lock_irqsave(&pendowner->pi_lock, flags);
-       if (current->prio >= pendowner->prio) {
+       if (task->prio >= pendowner->prio) {
                spin_unlock_irqrestore(&pendowner->pi_lock, flags);
                return 0;
        }
@@ -338,21 +339,21 @@ static inline int try_to_steal_lock(struct rt_mutex *lock)
         * We are going to steal the lock and a waiter was
         * enqueued on the pending owners pi_waiters queue. So
         * we have to enqueue this waiter into
-        * current->pi_waiters list. This covers the case,
-        * where current is boosted because it holds another
+        * task->pi_waiters list. This covers the case,
+        * where task is boosted because it holds another
         * lock and gets unboosted because the booster is
         * interrupted, so we would delay a waiter with higher
-        * priority as current->normal_prio.
+        * priority as task->normal_prio.
         *
         * Note: in the rare case of a SCHED_OTHER task changing
         * its priority and thus stealing the lock, next->task
-        * might be current:
+        * might be task:
         */
-       if (likely(next->task != current)) {
-               spin_lock_irqsave(&current->pi_lock, flags);
-               plist_add(&next->pi_list_entry, &current->pi_waiters);
-               __rt_mutex_adjust_prio(current);
-               spin_unlock_irqrestore(&current->pi_lock, flags);
+       if (likely(next->task != task)) {
+               spin_lock_irqsave(&task->pi_lock, flags);
+               plist_add(&next->pi_list_entry, &task->pi_waiters);
+               __rt_mutex_adjust_prio(task);
+               spin_unlock_irqrestore(&task->pi_lock, flags);
        }
        return 1;
 }
@@ -389,7 +390,7 @@ static int try_to_take_rt_mutex(struct rt_mutex *lock)
         */
        mark_rt_mutex_waiters(lock);
 
-       if (rt_mutex_owner(lock) && !try_to_steal_lock(lock))
+       if (rt_mutex_owner(lock) && !try_to_steal_lock(lock, current))
                return 0;
 
        /* We got the lock. */
@@ -411,6 +412,7 @@ static int try_to_take_rt_mutex(struct rt_mutex *lock)
  */
 static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
                                   struct rt_mutex_waiter *waiter,
+                                  struct task_struct *task,
                                   int detect_deadlock)
 {
        struct task_struct *owner = rt_mutex_owner(lock);
@@ -418,21 +420,21 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
        unsigned long flags;
        int chain_walk = 0, res;
 
-       spin_lock_irqsave(&current->pi_lock, flags);
-       __rt_mutex_adjust_prio(current);
-       waiter->task = current;
+       spin_lock_irqsave(&task->pi_lock, flags);
+       __rt_mutex_adjust_prio(task);
+       waiter->task = task;
        waiter->lock = lock;
-       plist_node_init(&waiter->list_entry, current->prio);
-       plist_node_init(&waiter->pi_list_entry, current->prio);
+       plist_node_init(&waiter->list_entry, task->prio);
+       plist_node_init(&waiter->pi_list_entry, task->prio);
 
        /* Get the top priority waiter on the lock */
        if (rt_mutex_has_waiters(lock))
                top_waiter = rt_mutex_top_waiter(lock);
        plist_add(&waiter->list_entry, &lock->wait_list);
 
-       current->pi_blocked_on = waiter;
+       task->pi_blocked_on = waiter;
 
-       spin_unlock_irqrestore(&current->pi_lock, flags);
+       spin_unlock_irqrestore(&task->pi_lock, flags);
 
        if (waiter == rt_mutex_top_waiter(lock)) {
                spin_lock_irqsave(&owner->pi_lock, flags);
@@ -460,7 +462,7 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
        spin_unlock(&lock->wait_lock);
 
        res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock, waiter,
-                                        current);
+                                        task);
 
        spin_lock(&lock->wait_lock);
 
@@ -605,37 +607,25 @@ void rt_mutex_adjust_pi(struct task_struct *task)
        rt_mutex_adjust_prio_chain(task, 0, NULL, NULL, task);
 }
 
-/*
- * Slow path lock function:
+/**
+ * __rt_mutex_slowlock() - Perform the wait-wake-try-to-take loop
+ * @lock:               the rt_mutex to take
+ * @state:              the state the task should block in (TASK_INTERRUPTIBLE
+ *                      or TASK_UNINTERRUPTIBLE)
+ * @timeout:            the pre-initialized and started timer, or NULL for none
+ * @waiter:             the pre-initialized rt_mutex_waiter
+ * @detect_deadlock:    passed to task_blocks_on_rt_mutex
+ *
+ * lock->wait_lock must be held by the caller.
  */
 static int __sched
-rt_mutex_slowlock(struct rt_mutex *lock, int state,
-                 struct hrtimer_sleeper *timeout,
-                 int detect_deadlock)
+__rt_mutex_slowlock(struct rt_mutex *lock, int state,
+                   struct hrtimer_sleeper *timeout,
+                   struct rt_mutex_waiter *waiter,
+                   int detect_deadlock)
 {
-       struct rt_mutex_waiter waiter;
        int ret = 0;
 
-       debug_rt_mutex_init_waiter(&waiter);
-       waiter.task = NULL;
-
-       spin_lock(&lock->wait_lock);
-
-       /* Try to acquire the lock again: */
-       if (try_to_take_rt_mutex(lock)) {
-               spin_unlock(&lock->wait_lock);
-               return 0;
-       }
-
-       set_current_state(state);
-
-       /* Setup the timer, when timeout != NULL */
-       if (unlikely(timeout)) {
-               hrtimer_start_expires(&timeout->timer, HRTIMER_MODE_ABS);
-               if (!hrtimer_active(&timeout->timer))
-                       timeout->task = NULL;
-       }
-
        for (;;) {
                /* Try to acquire the lock: */
                if (try_to_take_rt_mutex(lock))
@@ -656,19 +646,19 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state,
                }
 
                /*
-                * waiter.task is NULL the first time we come here and
+                * waiter->task is NULL the first time we come here and
                 * when we have been woken up by the previous owner
                 * but the lock got stolen by a higher prio task.
                 */
-               if (!waiter.task) {
-                       ret = task_blocks_on_rt_mutex(lock, &waiter,
+               if (!waiter->task) {
+                       ret = task_blocks_on_rt_mutex(lock, waiter, current,
                                                      detect_deadlock);
                        /*
                         * If we got woken up by the owner then start loop
                         * all over without going into schedule to try
                         * to get the lock now:
                         */
-                       if (unlikely(!waiter.task)) {
+                       if (unlikely(!waiter->task)) {
                                /*
                                 * Reset the return value. We might
                                 * have returned with -EDEADLK and the
@@ -684,15 +674,52 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state,
 
                spin_unlock(&lock->wait_lock);
 
-               debug_rt_mutex_print_deadlock(&waiter);
+               debug_rt_mutex_print_deadlock(waiter);
 
-               if (waiter.task)
+               if (waiter->task)
                        schedule_rt_mutex(lock);
 
                spin_lock(&lock->wait_lock);
                set_current_state(state);
        }
 
+       return ret;
+}
+
+/*
+ * Slow path lock function:
+ */
+static int __sched
+rt_mutex_slowlock(struct rt_mutex *lock, int state,
+                 struct hrtimer_sleeper *timeout,
+                 int detect_deadlock)
+{
+       struct rt_mutex_waiter waiter;
+       int ret = 0;
+
+       debug_rt_mutex_init_waiter(&waiter);
+       waiter.task = NULL;
+
+       spin_lock(&lock->wait_lock);
+
+       /* Try to acquire the lock again: */
+       if (try_to_take_rt_mutex(lock)) {
+               spin_unlock(&lock->wait_lock);
+               return 0;
+       }
+
+       set_current_state(state);
+
+       /* Setup the timer, when timeout != NULL */
+       if (unlikely(timeout)) {
+               hrtimer_start_expires(&timeout->timer, HRTIMER_MODE_ABS);
+               if (!hrtimer_active(&timeout->timer))
+                       timeout->task = NULL;
+       }
+
+       ret = __rt_mutex_slowlock(lock, state, timeout, &waiter,
+                                 detect_deadlock);
+
        set_current_state(TASK_RUNNING);
 
        if (unlikely(waiter.task))
@@ -864,9 +891,9 @@ int __sched rt_mutex_lock_interruptible(struct rt_mutex *lock,
 EXPORT_SYMBOL_GPL(rt_mutex_lock_interruptible);
 
 /**
- * rt_mutex_lock_interruptible_ktime - lock a rt_mutex interruptible
- *                                    the timeout structure is provided
- *                                    by the caller
+ * rt_mutex_timed_lock - lock a rt_mutex interruptible
+ *                     the timeout structure is provided
+ *                     by the caller
  *
  * @lock:              the rt_mutex to be locked
  * @timeout:           timeout structure or NULL (no timeout)
@@ -913,7 +940,7 @@ void __sched rt_mutex_unlock(struct rt_mutex *lock)
 }
 EXPORT_SYMBOL_GPL(rt_mutex_unlock);
 
-/***
+/**
  * rt_mutex_destroy - mark a mutex unusable
  * @lock: the mutex to be destroyed
  *
@@ -985,6 +1012,59 @@ void rt_mutex_proxy_unlock(struct rt_mutex *lock,
        rt_mutex_deadlock_account_unlock(proxy_owner);
 }
 
+/**
+ * rt_mutex_start_proxy_lock() - Start lock acquisition for another task
+ * @lock:              the rt_mutex to take
+ * @waiter:            the pre-initialized rt_mutex_waiter
+ * @task:              the task to prepare
+ * @detect_deadlock:   perform deadlock detection (1) or not (0)
+ *
+ * Returns:
+ *  0 - task blocked on lock
+ *  1 - acquired the lock for task, caller should wake it up
+ * <0 - error
+ *
+ * Special API call for FUTEX_REQUEUE_PI support.
+ */
+int rt_mutex_start_proxy_lock(struct rt_mutex *lock,
+                             struct rt_mutex_waiter *waiter,
+                             struct task_struct *task, int detect_deadlock)
+{
+       int ret;
+
+       spin_lock(&lock->wait_lock);
+
+       mark_rt_mutex_waiters(lock);
+
+       if (!rt_mutex_owner(lock) || try_to_steal_lock(lock, task)) {
+               /* We got the lock for task. */
+               debug_rt_mutex_lock(lock);
+
+               rt_mutex_set_owner(lock, task, 0);
+
+               rt_mutex_deadlock_account_lock(lock, task);
+               return 1;
+       }
+
+       ret = task_blocks_on_rt_mutex(lock, waiter, task, detect_deadlock);
+
+
+       if (ret && !waiter->task) {
+               /*
+                * Reset the return value. We might have
+                * returned with -EDEADLK and the owner
+                * released the lock while we were walking the
+                * pi chain.  Let the waiter sort it out.
+                */
+               ret = 0;
+       }
+       spin_unlock(&lock->wait_lock);
+
+       debug_rt_mutex_print_deadlock(waiter);
+
+       return ret;
+}
+
 /**
  * rt_mutex_next_owner - return the next owner of the lock
  *
@@ -1004,3 +1084,57 @@ struct task_struct *rt_mutex_next_owner(struct rt_mutex *lock)
 
        return rt_mutex_top_waiter(lock)->task;
 }
+
+/**
+ * rt_mutex_finish_proxy_lock() - Complete lock acquisition
+ * @lock:              the rt_mutex we were woken on
+ * @to:                        the timeout, null if none. hrtimer should already have
+ *                     been started.
+ * @waiter:            the pre-initialized rt_mutex_waiter
+ * @detect_deadlock:   perform deadlock detection (1) or not (0)
+ *
+ * Complete the lock acquisition started our behalf by another thread.
+ *
+ * Returns:
+ *  0 - success
+ * <0 - error, one of -EINTR, -ETIMEDOUT, or -EDEADLK
+ *
+ * Special API call for PI-futex requeue support
+ */
+int rt_mutex_finish_proxy_lock(struct rt_mutex *lock,
+                              struct hrtimer_sleeper *to,
+                              struct rt_mutex_waiter *waiter,
+                              int detect_deadlock)
+{
+       int ret;
+
+       spin_lock(&lock->wait_lock);
+
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       ret = __rt_mutex_slowlock(lock, TASK_INTERRUPTIBLE, to, waiter,
+                                 detect_deadlock);
+
+       set_current_state(TASK_RUNNING);
+
+       if (unlikely(waiter->task))
+               remove_waiter(lock, waiter);
+
+       /*
+        * try_to_take_rt_mutex() sets the waiter bit unconditionally. We might
+        * have to fix that up.
+        */
+       fixup_rt_mutex_waiters(lock);
+
+       spin_unlock(&lock->wait_lock);
+
+       /*
+        * Readjust priority, when we did not get the lock. We might have been
+        * the pending owner and boosted. Since we did not take the lock, the
+        * PI boost has to go.
+        */
+       if (unlikely(ret))
+               rt_mutex_adjust_prio(current);
+
+       return ret;
+}
index e124bf5800ea140ceeb936c7cba6429fea0e49b5..97a2f81866afdb6507607c4a30348f3f74564e0e 100644 (file)
@@ -120,6 +120,14 @@ extern void rt_mutex_init_proxy_locked(struct rt_mutex *lock,
                                       struct task_struct *proxy_owner);
 extern void rt_mutex_proxy_unlock(struct rt_mutex *lock,
                                  struct task_struct *proxy_owner);
+extern int rt_mutex_start_proxy_lock(struct rt_mutex *lock,
+                                    struct rt_mutex_waiter *waiter,
+                                    struct task_struct *task,
+                                    int detect_deadlock);
+extern int rt_mutex_finish_proxy_lock(struct rt_mutex *lock,
+                                     struct hrtimer_sleeper *to,
+                                     struct rt_mutex_waiter *waiter,
+                                     int detect_deadlock);
 
 #ifdef CONFIG_DEBUG_RT_MUTEXES
 # include "rtmutex-debug.h"
index 26efa475bdc143f6e4459067c18ce57e71608764..14c447ae5d53a23235a44f426737e46313df7f57 100644 (file)
 #include <linux/debugfs.h>
 #include <linux/ctype.h>
 #include <linux/ftrace.h>
-#include <trace/sched.h>
 
 #include <asm/tlb.h>
 #include <asm/irq_regs.h>
 
 #include "sched_cpupri.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/sched.h>
+
 /*
  * Convert user-nice values [ -20 ... 0 ... 19 ]
  * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
  */
 #define RUNTIME_INF    ((u64)~0ULL)
 
-DEFINE_TRACE(sched_wait_task);
-DEFINE_TRACE(sched_wakeup);
-DEFINE_TRACE(sched_wakeup_new);
-DEFINE_TRACE(sched_switch);
-DEFINE_TRACE(sched_migrate_task);
-
 #ifdef CONFIG_SMP
 
 static void double_rq_lock(struct rq *rq1, struct rq *rq2);
@@ -630,6 +626,10 @@ struct rq {
        struct list_head migration_queue;
 #endif
 
+       /* calc_load related fields */
+       unsigned long calc_load_update;
+       long calc_load_active;
+
 #ifdef CONFIG_SCHED_HRTICK
 #ifdef CONFIG_SMP
        int hrtick_csd_pending;
@@ -1728,6 +1728,8 @@ static void cfs_rq_set_shares(struct cfs_rq *cfs_rq, unsigned long shares)
 }
 #endif
 
+static void calc_load_account_active(struct rq *this_rq);
+
 #include "sched_stats.h"
 #include "sched_idletask.c"
 #include "sched_fair.c"
@@ -1958,7 +1960,7 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
 
        clock_offset = old_rq->clock - new_rq->clock;
 
-       trace_sched_migrate_task(p, task_cpu(p), new_cpu);
+       trace_sched_migrate_task(p, new_cpu);
 
 #ifdef CONFIG_SCHEDSTATS
        if (p->se.wait_start)
@@ -2014,6 +2016,49 @@ migrate_task(struct task_struct *p, int dest_cpu, struct migration_req *req)
        return 1;
 }
 
+/*
+ * wait_task_context_switch -  wait for a thread to complete at least one
+ *                             context switch.
+ *
+ * @p must not be current.
+ */
+void wait_task_context_switch(struct task_struct *p)
+{
+       unsigned long nvcsw, nivcsw, flags;
+       int running;
+       struct rq *rq;
+
+       nvcsw   = p->nvcsw;
+       nivcsw  = p->nivcsw;
+       for (;;) {
+               /*
+                * The runqueue is assigned before the actual context
+                * switch. We need to take the runqueue lock.
+                *
+                * We could check initially without the lock but it is
+                * very likely that we need to take the lock in every
+                * iteration.
+                */
+               rq = task_rq_lock(p, &flags);
+               running = task_running(rq, p);
+               task_rq_unlock(rq, &flags);
+
+               if (likely(!running))
+                       break;
+               /*
+                * The switch count is incremented before the actual
+                * context switch. We thus wait for two switches to be
+                * sure at least one completed.
+                */
+               if ((p->nvcsw - nvcsw) > 1)
+                       break;
+               if ((p->nivcsw - nivcsw) > 1)
+                       break;
+
+               cpu_relax();
+       }
+}
+
 /*
  * wait_task_inactive - wait for a thread to unschedule.
  *
@@ -2458,6 +2503,17 @@ out:
        return success;
 }
 
+/**
+ * wake_up_process - Wake up a specific process
+ * @p: The process to be woken up.
+ *
+ * Attempt to wake up the nominated process and move it to the set of runnable
+ * processes.  Returns 1 if the process was woken up, 0 if it was already
+ * running.
+ *
+ * It may be assumed that this function implies a write memory barrier before
+ * changing the task state if and only if any tasks are woken up.
+ */
 int wake_up_process(struct task_struct *p)
 {
        return try_to_wake_up(p, TASK_ALL, 0);
@@ -2766,7 +2822,7 @@ context_switch(struct rq *rq, struct task_struct *prev,
         * combine the page table reload and the switch backend into
         * one hypercall.
         */
-       arch_enter_lazy_cpu_mode();
+       arch_start_context_switch(prev);
 
        if (unlikely(!mm)) {
                next->active_mm = oldmm;
@@ -2856,19 +2912,72 @@ unsigned long nr_iowait(void)
        return sum;
 }
 
-unsigned long nr_active(void)
+/* Variables and functions for calc_load */
+static atomic_long_t calc_load_tasks;
+static unsigned long calc_load_update;
+unsigned long avenrun[3];
+EXPORT_SYMBOL(avenrun);
+
+/**
+ * get_avenrun - get the load average array
+ * @loads:     pointer to dest load array
+ * @offset:    offset to add
+ * @shift:     shift count to shift the result left
+ *
+ * These values are estimates at best, so no need for locking.
+ */
+void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
+{
+       loads[0] = (avenrun[0] + offset) << shift;
+       loads[1] = (avenrun[1] + offset) << shift;
+       loads[2] = (avenrun[2] + offset) << shift;
+}
+
+static unsigned long
+calc_load(unsigned long load, unsigned long exp, unsigned long active)
 {
-       unsigned long i, running = 0, uninterruptible = 0;
+       load *= exp;
+       load += active * (FIXED_1 - exp);
+       return load >> FSHIFT;
+}
 
-       for_each_online_cpu(i) {
-               running += cpu_rq(i)->nr_running;
-               uninterruptible += cpu_rq(i)->nr_uninterruptible;
-       }
+/*
+ * calc_load - update the avenrun load estimates 10 ticks after the
+ * CPUs have updated calc_load_tasks.
+ */
+void calc_global_load(void)
+{
+       unsigned long upd = calc_load_update + 10;
+       long active;
 
-       if (unlikely((long)uninterruptible < 0))
-               uninterruptible = 0;
+       if (time_before(jiffies, upd))
+               return;
 
-       return running + uninterruptible;
+       active = atomic_long_read(&calc_load_tasks);
+       active = active > 0 ? active * FIXED_1 : 0;
+
+       avenrun[0] = calc_load(avenrun[0], EXP_1, active);
+       avenrun[1] = calc_load(avenrun[1], EXP_5, active);
+       avenrun[2] = calc_load(avenrun[2], EXP_15, active);
+
+       calc_load_update += LOAD_FREQ;
+}
+
+/*
+ * Either called from update_cpu_load() or from a cpu going idle
+ */
+static void calc_load_account_active(struct rq *this_rq)
+{
+       long nr_active, delta;
+
+       nr_active = this_rq->nr_running;
+       nr_active += (long) this_rq->nr_uninterruptible;
+
+       if (nr_active != this_rq->calc_load_active) {
+               delta = nr_active - this_rq->calc_load_active;
+               this_rq->calc_load_active = nr_active;
+               atomic_long_add(delta, &calc_load_tasks);
+       }
 }
 
 /*
@@ -2899,6 +3008,11 @@ static void update_cpu_load(struct rq *this_rq)
                        new_load += scale-1;
                this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) >> i;
        }
+
+       if (time_after_eq(jiffies, this_rq->calc_load_update)) {
+               this_rq->calc_load_update += LOAD_FREQ;
+               calc_load_account_active(this_rq);
+       }
 }
 
 #ifdef CONFIG_SMP
@@ -4240,10 +4354,126 @@ static void active_load_balance(struct rq *busiest_rq, int busiest_cpu)
 static struct {
        atomic_t load_balancer;
        cpumask_var_t cpu_mask;
+       cpumask_var_t ilb_grp_nohz_mask;
 } nohz ____cacheline_aligned = {
        .load_balancer = ATOMIC_INIT(-1),
 };
 
+#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
+/**
+ * lowest_flag_domain - Return lowest sched_domain containing flag.
+ * @cpu:       The cpu whose lowest level of sched domain is to
+ *             be returned.
+ * @flag:      The flag to check for the lowest sched_domain
+ *             for the given cpu.
+ *
+ * Returns the lowest sched_domain of a cpu which contains the given flag.
+ */
+static inline struct sched_domain *lowest_flag_domain(int cpu, int flag)
+{
+       struct sched_domain *sd;
+
+       for_each_domain(cpu, sd)
+               if (sd && (sd->flags & flag))
+                       break;
+
+       return sd;
+}
+
+/**
+ * for_each_flag_domain - Iterates over sched_domains containing the flag.
+ * @cpu:       The cpu whose domains we're iterating over.
+ * @sd:                variable holding the value of the power_savings_sd
+ *             for cpu.
+ * @flag:      The flag to filter the sched_domains to be iterated.
+ *
+ * Iterates over all the scheduler domains for a given cpu that has the 'flag'
+ * set, starting from the lowest sched_domain to the highest.
+ */
+#define for_each_flag_domain(cpu, sd, flag) \
+       for (sd = lowest_flag_domain(cpu, flag); \
+               (sd && (sd->flags & flag)); sd = sd->parent)
+
+/**
+ * is_semi_idle_group - Checks if the given sched_group is semi-idle.
+ * @ilb_group: group to be checked for semi-idleness
+ *
+ * Returns:    1 if the group is semi-idle. 0 otherwise.
+ *
+ * We define a sched_group to be semi idle if it has atleast one idle-CPU
+ * and atleast one non-idle CPU. This helper function checks if the given
+ * sched_group is semi-idle or not.
+ */
+static inline int is_semi_idle_group(struct sched_group *ilb_group)
+{
+       cpumask_and(nohz.ilb_grp_nohz_mask, nohz.cpu_mask,
+                                       sched_group_cpus(ilb_group));
+
+       /*
+        * A sched_group is semi-idle when it has atleast one busy cpu
+        * and atleast one idle cpu.
+        */
+       if (cpumask_empty(nohz.ilb_grp_nohz_mask))
+               return 0;
+
+       if (cpumask_equal(nohz.ilb_grp_nohz_mask, sched_group_cpus(ilb_group)))
+               return 0;
+
+       return 1;
+}
+/**
+ * find_new_ilb - Finds the optimum idle load balancer for nomination.
+ * @cpu:       The cpu which is nominating a new idle_load_balancer.
+ *
+ * Returns:    Returns the id of the idle load balancer if it exists,
+ *             Else, returns >= nr_cpu_ids.
+ *
+ * This algorithm picks the idle load balancer such that it belongs to a
+ * semi-idle powersavings sched_domain. The idea is to try and avoid
+ * completely idle packages/cores just for the purpose of idle load balancing
+ * when there are other idle cpu's which are better suited for that job.
+ */
+static int find_new_ilb(int cpu)
+{
+       struct sched_domain *sd;
+       struct sched_group *ilb_group;
+
+       /*
+        * Have idle load balancer selection from semi-idle packages only
+        * when power-aware load balancing is enabled
+        */
+       if (!(sched_smt_power_savings || sched_mc_power_savings))
+               goto out_done;
+
+       /*
+        * Optimize for the case when we have no idle CPUs or only one
+        * idle CPU. Don't walk the sched_domain hierarchy in such cases
+        */
+       if (cpumask_weight(nohz.cpu_mask) < 2)
+               goto out_done;
+
+       for_each_flag_domain(cpu, sd, SD_POWERSAVINGS_BALANCE) {
+               ilb_group = sd->groups;
+
+               do {
+                       if (is_semi_idle_group(ilb_group))
+                               return cpumask_first(nohz.ilb_grp_nohz_mask);
+
+                       ilb_group = ilb_group->next;
+
+               } while (ilb_group != sd->groups);
+       }
+
+out_done:
+       return cpumask_first(nohz.cpu_mask);
+}
+#else /*  (CONFIG_SCHED_MC || CONFIG_SCHED_SMT) */
+static inline int find_new_ilb(int call_cpu)
+{
+       return cpumask_first(nohz.cpu_mask);
+}
+#endif
+
 /*
  * This routine will try to nominate the ilb (idle load balancing)
  * owner among the cpus whose ticks are stopped. ilb owner will do the idle
@@ -4298,8 +4528,24 @@ int select_nohz_load_balancer(int stop_tick)
                        /* make me the ilb owner */
                        if (atomic_cmpxchg(&nohz.load_balancer, -1, cpu) == -1)
                                return 1;
-               } else if (atomic_read(&nohz.load_balancer) == cpu)
+               } else if (atomic_read(&nohz.load_balancer) == cpu) {
+                       int new_ilb;
+
+                       if (!(sched_smt_power_savings ||
+                                               sched_mc_power_savings))
+                               return 1;
+                       /*
+                        * Check to see if there is a more power-efficient
+                        * ilb.
+                        */
+                       new_ilb = find_new_ilb(cpu);
+                       if (new_ilb < nr_cpu_ids && new_ilb != cpu) {
+                               atomic_set(&nohz.load_balancer, -1);
+                               resched_cpu(new_ilb);
+                               return 0;
+                       }
                        return 1;
+               }
        } else {
                if (!cpumask_test_cpu(cpu, nohz.cpu_mask))
                        return 0;
@@ -4468,15 +4714,7 @@ static inline void trigger_load_balance(struct rq *rq, int cpu)
                }
 
                if (atomic_read(&nohz.load_balancer) == -1) {
-                       /*
-                        * simple selection for now: Nominate the
-                        * first cpu in the nohz list to be the next
-                        * ilb owner.
-                        *
-                        * TBD: Traverse the sched domains and nominate
-                        * the nearest cpu in the nohz.cpu_mask.
-                        */
-                       int ilb = cpumask_first(nohz.cpu_mask);
+                       int ilb = find_new_ilb(cpu);
 
                        if (ilb < nr_cpu_ids)
                                resched_cpu(ilb);
@@ -5007,13 +5245,15 @@ 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);
@@ -5070,15 +5310,9 @@ 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)))
+       if (need_resched())
                goto need_resched;
 }
 EXPORT_SYMBOL(schedule);
@@ -5221,7 +5455,7 @@ EXPORT_SYMBOL(default_wake_function);
  * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns
  * zero in this (rare) case, and we handle it by continuing to scan the queue.
  */
-void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
+static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
                        int nr_exclusive, int sync, void *key)
 {
        wait_queue_t *curr, *next;
@@ -5241,6 +5475,9 @@ void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
  * @mode: which threads
  * @nr_exclusive: how many wake-one or wake-many threads to wake up
  * @key: is directly passed to the wakeup function
+ *
+ * It may be assumed that this function implies a write memory barrier before
+ * changing the task state if and only if any tasks are woken up.
  */
 void __wake_up(wait_queue_head_t *q, unsigned int mode,
                        int nr_exclusive, void *key)
@@ -5279,6 +5516,9 @@ void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key)
  * with each other. This can prevent needless bouncing between CPUs.
  *
  * On UP it can prevent extra preemption.
+ *
+ * It may be assumed that this function implies a write memory barrier before
+ * changing the task state if and only if any tasks are woken up.
  */
 void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode,
                        int nr_exclusive, void *key)
@@ -5315,6 +5555,9 @@ EXPORT_SYMBOL_GPL(__wake_up_sync);        /* For internal use only */
  * awakened in the same order in which they were queued.
  *
  * See also complete_all(), wait_for_completion() and related routines.
+ *
+ * It may be assumed that this function implies a write memory barrier before
+ * changing the task state if and only if any tasks are woken up.
  */
 void complete(struct completion *x)
 {
@@ -5332,6 +5575,9 @@ EXPORT_SYMBOL(complete);
  * @x:  holds the state of this particular completion
  *
  * This will wake up all threads waiting on this particular completion event.
+ *
+ * It may be assumed that this function implies a write memory barrier before
+ * changing the task state if and only if any tasks are woken up.
  */
 void complete_all(struct completion *x)
 {
@@ -6490,8 +6736,9 @@ void sched_show_task(struct task_struct *p)
 #ifdef CONFIG_DEBUG_STACK_USAGE
        free = stack_not_used(p);
 #endif
-       printk(KERN_CONT "%5lu %5d %6d\n", free,
-               task_pid_nr(p), task_pid_nr(p->real_parent));
+       printk(KERN_CONT "%5lu %5d %6d 0x%08lx\n", free,
+               task_pid_nr(p), task_pid_nr(p->real_parent),
+               (unsigned long)task_thread_info(p)->flags);
 
        show_stack(p, NULL);
 }
@@ -6970,6 +7217,14 @@ static void migrate_dead_tasks(unsigned int dead_cpu)
 
        }
 }
+
+/*
+ * remove the tasks which were accounted by rq from calc_load_tasks.
+ */
+static void calc_global_load_remove(struct rq *rq)
+{
+       atomic_long_sub(rq->calc_load_active, &calc_load_tasks);
+}
 #endif /* CONFIG_HOTPLUG_CPU */
 
 #if defined(CONFIG_SCHED_DEBUG) && defined(CONFIG_SYSCTL)
@@ -7204,6 +7459,8 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
                /* Update our root-domain */
                rq = cpu_rq(cpu);
                spin_lock_irqsave(&rq->lock, flags);
+               rq->calc_load_update = calc_load_update;
+               rq->calc_load_active = 0;
                if (rq->rd) {
                        BUG_ON(!cpumask_test_cpu(cpu, rq->rd->span));
 
@@ -7243,7 +7500,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
                cpuset_unlock();
                migrate_nr_uninterruptible(rq);
                BUG_ON(rq->nr_running != 0);
-
+               calc_global_load_remove(rq);
                /*
                 * No need to migrate the tasks: it was best-effort if
                 * they didn't take sched_hotcpu_mutex. Just wake up
@@ -7753,8 +8010,9 @@ int sched_smt_power_savings = 0, sched_mc_power_savings = 0;
 
 /*
  * The cpus mask in sched_group and sched_domain hangs off the end.
- * FIXME: use cpumask_var_t or dynamic percpu alloc to avoid wasting space
- * for nr_cpu_ids < CONFIG_NR_CPUS.
+ *
+ * ( See the the comments in include/linux/sched.h:struct sched_group
+ *   and struct sched_domain. )
  */
 struct static_sched_group {
        struct sched_group sg;
@@ -7875,7 +8133,7 @@ static void init_numa_sched_groups_power(struct sched_group *group_head)
                        struct sched_domain *sd;
 
                        sd = &per_cpu(phys_domains, j).sd;
-                       if (j != cpumask_first(sched_group_cpus(sd->groups))) {
+                       if (j != group_first_cpu(sd->groups)) {
                                /*
                                 * Only add "power" once for each
                                 * physical package.
@@ -7953,7 +8211,7 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd)
 
        WARN_ON(!sd || !sd->groups);
 
-       if (cpu != cpumask_first(sched_group_cpus(sd->groups)))
+       if (cpu != group_first_cpu(sd->groups))
                return;
 
        child = sd->child;
@@ -8938,6 +9196,8 @@ void __init sched_init(void)
                rq = cpu_rq(i);
                spin_lock_init(&rq->lock);
                rq->nr_running = 0;
+               rq->calc_load_active = 0;
+               rq->calc_load_update = jiffies + LOAD_FREQ;
                init_cfs_rq(&rq->cfs, rq);
                init_rt_rq(&rq->rt, rq);
 #ifdef CONFIG_FAIR_GROUP_SCHED
@@ -9045,6 +9305,9 @@ void __init sched_init(void)
         * when this runqueue becomes "idle".
         */
        init_idle(current, smp_processor_id());
+
+       calc_load_update = jiffies + LOAD_FREQ;
+
        /*
         * During early bootup we pretend to be a normal task:
         */
@@ -9055,6 +9318,7 @@ void __init sched_init(void)
 #ifdef CONFIG_SMP
 #ifdef CONFIG_NO_HZ
        alloc_bootmem_cpumask_var(&nohz.cpu_mask);
+       alloc_bootmem_cpumask_var(&nohz.ilb_grp_nohz_mask);
 #endif
        alloc_bootmem_cpumask_var(&cpu_isolated_map);
 #endif /* SMP */
@@ -9800,6 +10064,13 @@ static int sched_rt_global_constraints(void)
        if (sysctl_sched_rt_period <= 0)
                return -EINVAL;
 
+       /*
+        * There's always some RT tasks in the root group
+        * -- migration, kstopmachine etc..
+        */
+       if (sysctl_sched_rt_runtime == 0)
+               return -EBUSY;
+
        spin_lock_irqsave(&def_rt_bandwidth.rt_runtime_lock, flags);
        for_each_possible_cpu(i) {
                struct rt_rq *rt_rq = &cpu_rq(i)->rt;
index 3816f217f119ef635cf169f268b5140c6e0f66c6..5f9650e8fe7587938de1bfa71e48cd4a04061d36 100644 (file)
@@ -1487,17 +1487,10 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int sync)
 
        find_matching_se(&se, &pse);
 
-       while (se) {
-               BUG_ON(!pse);
+       BUG_ON(!pse);
 
-               if (wakeup_preempt_entity(se, pse) == 1) {
-                       resched_task(curr);
-                       break;
-               }
-
-               se = parent_entity(se);
-               pse = parent_entity(pse);
-       }
+       if (wakeup_preempt_entity(se, pse) == 1)
+               resched_task(curr);
 }
 
 static struct task_struct *pick_next_task_fair(struct rq *rq)
index 8a21a2e28c13ac2e4620e980888702e22a4f2387..499672c10cbd615141a362cafe804711bbcf1ff3 100644 (file)
@@ -22,7 +22,8 @@ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int sy
 static struct task_struct *pick_next_task_idle(struct rq *rq)
 {
        schedstat_inc(rq, sched_goidle);
-
+       /* adjust the active tasks as we might go into a long sleep */
+       calc_load_account_active(rq);
        return rq->idle;
 }
 
index d8034737db4cb86f8adca044560a3765ac65dba5..809a228019adeb06c8979d86f52473a0d4a168ac 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/freezer.h>
 #include <linux/pid_namespace.h>
 #include <linux/nsproxy.h>
-#include <trace/sched.h>
+#include <trace/events/sched.h>
 
 #include <asm/param.h>
 #include <asm/uaccess.h>
@@ -41,8 +41,6 @@
 
 static struct kmem_cache *sigqueue_cachep;
 
-DEFINE_TRACE(sched_signal_send);
-
 static void __user *sig_handler(struct task_struct *t, int sig)
 {
        return t->sighand->action[sig - 1].sa.sa_handler;
@@ -249,14 +247,19 @@ void flush_sigqueue(struct sigpending *queue)
 /*
  * Flush all pending signals for a task.
  */
+void __flush_signals(struct task_struct *t)
+{
+       clear_tsk_thread_flag(t, TIF_SIGPENDING);
+       flush_sigqueue(&t->pending);
+       flush_sigqueue(&t->signal->shared_pending);
+}
+
 void flush_signals(struct task_struct *t)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&t->sighand->siglock, flags);
-       clear_tsk_thread_flag(t, TIF_SIGPENDING);
-       flush_sigqueue(&t->pending);
-       flush_sigqueue(&t->signal->shared_pending);
+       __flush_signals(t);
        spin_unlock_irqrestore(&t->sighand->siglock, flags);
 }
 
@@ -2278,24 +2281,17 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
        return kill_something_info(sig, &info, pid);
 }
 
-static int do_tkill(pid_t tgid, pid_t pid, int sig)
+static int
+do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)
 {
-       int error;
-       struct siginfo info;
        struct task_struct *p;
        unsigned long flags;
-
-       error = -ESRCH;
-       info.si_signo = sig;
-       info.si_errno = 0;
-       info.si_code = SI_TKILL;
-       info.si_pid = task_tgid_vnr(current);
-       info.si_uid = current_uid();
+       int error = -ESRCH;
 
        rcu_read_lock();
        p = find_task_by_vpid(pid);
        if (p && (tgid <= 0 || task_tgid_vnr(p) == tgid)) {
-               error = check_kill_permission(sig, &info, p);
+               error = check_kill_permission(sig, info, p);
                /*
                 * The null signal is a permissions and process existence
                 * probe.  No signal is actually delivered.
@@ -2305,7 +2301,7 @@ static int do_tkill(pid_t tgid, pid_t pid, int sig)
                 * signal is private anyway.
                 */
                if (!error && sig && lock_task_sighand(p, &flags)) {
-                       error = specific_send_sig_info(sig, &info, p);
+                       error = specific_send_sig_info(sig, info, p);
                        unlock_task_sighand(p, &flags);
                }
        }
@@ -2314,6 +2310,19 @@ static int do_tkill(pid_t tgid, pid_t pid, int sig)
        return error;
 }
 
+static int do_tkill(pid_t tgid, pid_t pid, int sig)
+{
+       struct siginfo info;
+
+       info.si_signo = sig;
+       info.si_errno = 0;
+       info.si_code = SI_TKILL;
+       info.si_pid = task_tgid_vnr(current);
+       info.si_uid = current_uid();
+
+       return do_send_specific(tgid, pid, sig, &info);
+}
+
 /**
  *  sys_tgkill - send signal to one specific thread
  *  @tgid: the thread group ID of the thread
@@ -2363,6 +2372,32 @@ SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig,
        return kill_proc_info(sig, &info, pid);
 }
 
+long do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info)
+{
+       /* This is only valid for single tasks */
+       if (pid <= 0 || tgid <= 0)
+               return -EINVAL;
+
+       /* Not even root can pretend to send signals from the kernel.
+          Nor can they impersonate a kill(), which adds source info.  */
+       if (info->si_code >= 0)
+               return -EPERM;
+       info->si_signo = sig;
+
+       return do_send_specific(tgid, pid, sig, info);
+}
+
+SYSCALL_DEFINE4(rt_tgsigqueueinfo, pid_t, tgid, pid_t, pid, int, sig,
+               siginfo_t __user *, uinfo)
+{
+       siginfo_t info;
+
+       if (copy_from_user(&info, uinfo, sizeof(siginfo_t)))
+               return -EFAULT;
+
+       return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);
+}
+
 int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
 {
        struct task_struct *t = current;
index b525dd348511b0bda3b08c19ffef6df0cf053206..258885a543db60692a695aa682abb6c95f3ffcdf 100644 (file)
@@ -24,7 +24,9 @@
 #include <linux/ftrace.h>
 #include <linux/smp.h>
 #include <linux/tick.h>
-#include <trace/irq.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/irq.h>
 
 #include <asm/irq.h>
 /*
@@ -186,9 +188,6 @@ EXPORT_SYMBOL(local_bh_enable_ip);
  */
 #define MAX_SOFTIRQ_RESTART 10
 
-DEFINE_TRACE(softirq_entry);
-DEFINE_TRACE(softirq_exit);
-
 asmlinkage void __do_softirq(void)
 {
        struct softirq_action *h;
@@ -828,7 +827,7 @@ int __init __weak arch_early_irq_init(void)
        return 0;
 }
 
-int __weak arch_init_chip_data(struct irq_desc *desc, int cpu)
+int __weak arch_init_chip_data(struct irq_desc *desc, int node)
 {
        return 0;
 }
index b2970d56fb7678d6493e44c766db536f691656b7..944ba03cae199ad6139f96f65113bca007fe4fda 100644 (file)
@@ -114,6 +114,7 @@ static int ngroups_max = NGROUPS_MAX;
 
 #ifdef CONFIG_MODULES
 extern char modprobe_path[];
+extern int modules_disabled;
 #endif
 #ifdef CONFIG_CHR_DEV_SG
 extern int sg_big_buff;
@@ -534,6 +535,17 @@ static struct ctl_table kern_table[] = {
                .proc_handler   = &proc_dostring,
                .strategy       = &sysctl_string,
        },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "modules_disabled",
+               .data           = &modules_disabled,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               /* only handle a transition from default "0" to "1" */
+               .proc_handler   = &proc_dointvec_minmax,
+               .extra1         = &one,
+               .extra2         = &one,
+       },
 #endif
 #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
        {
@@ -729,6 +741,14 @@ static struct ctl_table kern_table[] = {
                .mode           = 0444,
                .proc_handler   = &proc_dointvec,
        },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "bootloader_version",
+               .data           = &bootloader_version,
+               .maxlen         = sizeof (int),
+               .mode           = 0444,
+               .proc_handler   = &proc_dointvec,
+       },
        {
                .ctl_name       = CTL_UNNUMBERED,
                .procname       = "kstack_depth_to_print",
@@ -1225,7 +1245,6 @@ static struct ctl_table vm_table[] = {
                .strategy       = &sysctl_jiffies,
        },
 #endif
-#ifdef CONFIG_SECURITY
        {
                .ctl_name       = CTL_UNNUMBERED,
                .procname       = "mmap_min_addr",
@@ -1234,7 +1253,6 @@ static struct ctl_table vm_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_doulongvec_minmax,
        },
-#endif
 #ifdef CONFIG_NUMA
        {
                .ctl_name       = CTL_UNNUMBERED,
index ecfd7b5187e0af0a7e3db8767ddfbf539ff64c23..80189f6f1c5a1f7a326c9490e18f571fc8f49ea7 100644 (file)
@@ -402,9 +402,6 @@ int clocksource_register(struct clocksource *c)
        unsigned long flags;
        int ret;
 
-       /* save mult_orig on registration */
-       c->mult_orig = c->mult;
-
        spin_lock_irqsave(&clocksource_lock, flags);
        ret = clocksource_enqueue(c);
        if (!ret)
index 687dff49f6e7da5ec92199f6bbae08de57e5ba43..e8c77d9c633acbffc4872b8d0c4b8a9929d399c2 100644 (file)
@@ -22,7 +22,7 @@
 
 /*
  * This read-write spinlock protects us from races in SMP while
- * playing with xtime and avenrun.
+ * playing with xtime.
  */
 __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock);
 
@@ -77,6 +77,10 @@ static void clocksource_forward_now(void)
        clock->cycle_last = cycle_now;
 
        nsec = cyc2ns(clock, cycle_delta);
+
+       /* If arch requires, add in gettimeoffset() */
+       nsec += arch_gettimeoffset();
+
        timespec_add_ns(&xtime, nsec);
 
        nsec = ((s64)cycle_delta * clock->mult_orig) >> clock->shift;
@@ -111,6 +115,9 @@ void getnstimeofday(struct timespec *ts)
                /* convert to nanoseconds: */
                nsecs = cyc2ns(clock, cycle_delta);
 
+               /* If arch requires, add in gettimeoffset() */
+               nsecs += arch_gettimeoffset();
+
        } while (read_seqretry(&xtime_lock, seq));
 
        timespec_add_ns(ts, nsecs);
index cffffad01c31cf1670490f2860f0e5de0f25d301..a26ed294f938708241c41b19b35fff551506a56a 100644 (file)
@@ -1122,47 +1122,6 @@ void update_process_times(int user_tick)
        run_posix_cpu_timers(p);
 }
 
-/*
- * Nr of active tasks - counted in fixed-point numbers
- */
-static unsigned long count_active_tasks(void)
-{
-       return nr_active() * FIXED_1;
-}
-
-/*
- * Hmm.. Changed this, as the GNU make sources (load.c) seems to
- * imply that avenrun[] is the standard name for this kind of thing.
- * Nothing else seems to be standardized: the fractional size etc
- * all seem to differ on different machines.
- *
- * Requires xtime_lock to access.
- */
-unsigned long avenrun[3];
-
-EXPORT_SYMBOL(avenrun);
-
-/*
- * calc_load - given tick count, update the avenrun load estimates.
- * This is called while holding a write_lock on xtime_lock.
- */
-static inline void calc_load(unsigned long ticks)
-{
-       unsigned long active_tasks; /* fixed-point */
-       static int count = LOAD_FREQ;
-
-       count -= ticks;
-       if (unlikely(count < 0)) {
-               active_tasks = count_active_tasks();
-               do {
-                       CALC_LOAD(avenrun[0], EXP_1, active_tasks);
-                       CALC_LOAD(avenrun[1], EXP_5, active_tasks);
-                       CALC_LOAD(avenrun[2], EXP_15, active_tasks);
-                       count += LOAD_FREQ;
-               } while (count < 0);
-       }
-}
-
 /*
  * This function runs timers and the timer-tq in bottom half context.
  */
@@ -1186,16 +1145,6 @@ void run_local_timers(void)
        softlockup_tick();
 }
 
-/*
- * Called by the timer interrupt. xtime_lock must already be taken
- * by the timer IRQ!
- */
-static inline void update_times(unsigned long ticks)
-{
-       update_wall_time();
-       calc_load(ticks);
-}
-
 /*
  * The 64-bit jiffies value is not atomic - you MUST NOT read it
  * without sampling the sequence number in xtime_lock.
@@ -1205,7 +1154,8 @@ static inline void update_times(unsigned long ticks)
 void do_timer(unsigned long ticks)
 {
        jiffies_64 += ticks;
-       update_times(ticks);
+       update_wall_time();
+       calc_global_load();
 }
 
 #ifdef __ARCH_WANT_SYS_ALARM
@@ -1406,37 +1356,17 @@ int do_sysinfo(struct sysinfo *info)
 {
        unsigned long mem_total, sav_total;
        unsigned int mem_unit, bitcount;
-       unsigned long seq;
+       struct timespec tp;
 
        memset(info, 0, sizeof(struct sysinfo));
 
-       do {
-               struct timespec tp;
-               seq = read_seqbegin(&xtime_lock);
-
-               /*
-                * This is annoying.  The below is the same thing
-                * posix_get_clock_monotonic() does, but it wants to
-                * take the lock which we want to cover the loads stuff
-                * too.
-                */
-
-               getnstimeofday(&tp);
-               tp.tv_sec += wall_to_monotonic.tv_sec;
-               tp.tv_nsec += wall_to_monotonic.tv_nsec;
-               monotonic_to_bootbased(&tp);
-               if (tp.tv_nsec - NSEC_PER_SEC >= 0) {
-                       tp.tv_nsec = tp.tv_nsec - NSEC_PER_SEC;
-                       tp.tv_sec++;
-               }
-               info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0);
+       ktime_get_ts(&tp);
+       monotonic_to_bootbased(&tp);
+       info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0);
 
-               info->loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
-               info->loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
-               info->loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);
+       get_avenrun(info->loads, 0, SI_LOAD_SHIFT - FSHIFT);
 
-               info->procs = nr_threads;
-       } while (read_seqretry(&xtime_lock, seq));
+       info->procs = nr_threads;
 
        si_meminfo(info);
        si_swapinfo(info);
index 417d1985e29911784adbf506523462f009933c02..4a13e5a01ce318c62c75c991a8694096e4821f40 100644 (file)
@@ -48,6 +48,21 @@ config FTRACE_NMI_ENTER
        depends on HAVE_FTRACE_NMI_ENTER
        default y
 
+config EVENT_TRACING
+       select CONTEXT_SWITCH_TRACER
+       bool
+
+config CONTEXT_SWITCH_TRACER
+       select MARKERS
+       bool
+
+# All tracer options should select GENERIC_TRACER. For those options that are
+# enabled by all tracers (context switch and event tracer) they select TRACING.
+# This allows those options to appear when no other tracer is selected. But the
+# options do not appear when something else selects it. We need the two options
+# GENERIC_TRACER and TRACING to avoid circular dependencies to accomplish the
+# hidding of the automatic options options.
+
 config TRACING
        bool
        select DEBUG_FS
@@ -56,6 +71,11 @@ config TRACING
        select TRACEPOINTS
        select NOP_TRACER
        select BINARY_PRINTF
+       select EVENT_TRACING
+
+config GENERIC_TRACER
+       bool
+       select TRACING
 
 #
 # Minimum requirements an architecture has to meet for us to
@@ -73,14 +93,20 @@ config TRACING_SUPPORT
 
 if TRACING_SUPPORT
 
-menu "Tracers"
+menuconfig FTRACE
+       bool "Tracers"
+       default y if DEBUG_KERNEL
+       help
+        Enable the kernel tracing infrastructure.
+
+if FTRACE
 
 config FUNCTION_TRACER
        bool "Kernel Function Tracer"
        depends on HAVE_FUNCTION_TRACER
        select FRAME_POINTER
        select KALLSYMS
-       select TRACING
+       select GENERIC_TRACER
        select CONTEXT_SWITCH_TRACER
        help
          Enable the kernel to trace every kernel function. This is done
@@ -104,13 +130,14 @@ config FUNCTION_GRAPH_TRACER
          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"
        default n
        depends on TRACE_IRQFLAGS_SUPPORT
        depends on GENERIC_TIME
        select TRACE_IRQFLAGS
-       select TRACING
+       select GENERIC_TRACER
        select TRACER_MAX_TRACE
        help
          This option measures the time spent in irqs-off critical
@@ -131,7 +158,7 @@ config PREEMPT_TRACER
        default n
        depends on GENERIC_TIME
        depends on PREEMPT
-       select TRACING
+       select GENERIC_TRACER
        select TRACER_MAX_TRACE
        help
          This option measures the time spent in preemption off critical
@@ -150,7 +177,7 @@ config PREEMPT_TRACER
 config SYSPROF_TRACER
        bool "Sysprof Tracer"
        depends on X86
-       select TRACING
+       select GENERIC_TRACER
        select CONTEXT_SWITCH_TRACER
        help
          This tracer provides the trace needed by the 'Sysprof' userspace
@@ -158,40 +185,33 @@ config SYSPROF_TRACER
 
 config SCHED_TRACER
        bool "Scheduling Latency Tracer"
-       select TRACING
+       select GENERIC_TRACER
        select CONTEXT_SWITCH_TRACER
        select TRACER_MAX_TRACE
        help
          This tracer tracks the latency of the highest priority task
          to be scheduled in, starting from the point it has woken up.
 
-config CONTEXT_SWITCH_TRACER
-       bool "Trace process context switches"
-       select TRACING
-       select MARKERS
-       help
-         This tracer gets called from the context switch and records
-         all switching of tasks.
-
-config EVENT_TRACER
-       bool "Trace various events in the kernel"
+config ENABLE_DEFAULT_TRACERS
+       bool "Trace process context switches and events"
+       depends on !GENERIC_TRACER
        select TRACING
        help
          This tracer hooks to various trace points in the kernel
          allowing the user to pick and choose which trace point they
-         want to trace.
+         want to trace. It also includes the sched_switch tracer plugin.
 
 config FTRACE_SYSCALLS
        bool "Trace syscalls"
        depends on HAVE_FTRACE_SYSCALLS
-       select TRACING
+       select GENERIC_TRACER
        select KALLSYMS
        help
          Basic tracer to catch the syscall entry and exit events.
 
 config BOOT_TRACER
        bool "Trace boot initcalls"
-       select TRACING
+       select GENERIC_TRACER
        select CONTEXT_SWITCH_TRACER
        help
          This tracer helps developers to optimize boot times: it records
@@ -207,8 +227,36 @@ config BOOT_TRACER
          to enable this on bootup.
 
 config TRACE_BRANCH_PROFILING
+       bool
+       select GENERIC_TRACER
+
+choice
+       prompt "Branch Profiling"
+       default BRANCH_PROFILE_NONE
+       help
+        The branch profiling is a software profiler. It will add hooks
+        into the C conditionals to test which path a branch takes.
+
+        The likely/unlikely profiler only looks at the conditions that
+        are annotated with a likely or unlikely macro.
+
+        The "all branch" profiler will profile every if statement in the
+        kernel. This profiler will also enable the likely/unlikely
+        profiler as well.
+
+        Either of the above profilers add a bit of overhead to the system.
+        If unsure choose "No branch profiling".
+
+config BRANCH_PROFILE_NONE
+       bool "No branch profiling"
+       help
+        No branch profiling. Branch profiling adds a bit of overhead.
+        Only enable it if you want to analyse the branching behavior.
+        Otherwise keep it disabled.
+
+config PROFILE_ANNOTATED_BRANCHES
        bool "Trace likely/unlikely profiler"
-       select TRACING
+       select TRACE_BRANCH_PROFILING
        help
          This tracer profiles all the the likely and unlikely macros
          in the kernel. It will display the results in:
@@ -218,11 +266,9 @@ config TRACE_BRANCH_PROFILING
          Note: this will add a significant overhead, only turn this
          on if you need to profile the system's use of these macros.
 
-         Say N if unsure.
-
 config PROFILE_ALL_BRANCHES
        bool "Profile all if conditionals"
-       depends on TRACE_BRANCH_PROFILING
+       select TRACE_BRANCH_PROFILING
        help
          This tracer profiles all branch conditions. Every if ()
          taken in the kernel is recorded whether it hit or miss.
@@ -230,11 +276,12 @@ config PROFILE_ALL_BRANCHES
 
          /debugfs/tracing/profile_branch
 
+         This option also enables the likely/unlikely profiler.
+
          This configuration, when enabled, will impose a great overhead
          on the system. This should only be enabled when the system
          is to be analyzed
-
-         Say N if unsure.
+endchoice
 
 config TRACING_BRANCHES
        bool
@@ -261,7 +308,7 @@ config BRANCH_TRACER
 config POWER_TRACER
        bool "Trace power consumption behavior"
        depends on X86
-       select TRACING
+       select GENERIC_TRACER
        help
          This tracer helps developers to analyze and optimize the kernels
          power management decisions, specifically the C-state and P-state
@@ -295,14 +342,14 @@ config STACK_TRACER
 config HW_BRANCH_TRACER
        depends on HAVE_HW_BRANCH_TRACER
        bool "Trace hw branches"
-       select TRACING
+       select GENERIC_TRACER
        help
          This tracer records all branches on the system in a circular
          buffer giving access to the last N branches for each cpu.
 
 config KMEMTRACE
        bool "Trace SLAB allocations"
-       select TRACING
+       select GENERIC_TRACER
        help
          kmemtrace provides tracing for slab allocator functions, such as
          kmalloc, kfree, kmem_cache_alloc, kmem_cache_free etc.. Collected
@@ -322,7 +369,7 @@ config KMEMTRACE
 
 config WORKQUEUE_TRACER
        bool "Trace workqueues"
-       select TRACING
+       select GENERIC_TRACER
        help
          The workqueue tracer provides some statistical informations
           about each cpu workqueue thread such as the number of the
@@ -338,7 +385,7 @@ config BLK_DEV_IO_TRACE
        select RELAY
        select DEBUG_FS
        select TRACEPOINTS
-       select TRACING
+       select GENERIC_TRACER
        select STACKTRACE
        help
          Say Y here if you want to be able to trace the block layer actions
@@ -375,6 +422,20 @@ config DYNAMIC_FTRACE
         were made. If so, it runs stop_machine (stops all CPUS)
         and modifies the code to jump over the call to ftrace.
 
+config FUNCTION_PROFILER
+       bool "Kernel function profiler"
+       depends on FUNCTION_TRACER
+       default n
+       help
+        This option enables the kernel function profiler. A file is created
+        in debugfs called function_profile_enabled which defaults to zero.
+        When a 1 is echoed into this file profiling begins, and when a
+        zero is entered, profiling stops. A file in the trace_stats
+        directory called functions, that show the list of functions that
+        have been hit and their counters.
+
+        If in doubt, say N
+
 config FTRACE_MCOUNT_RECORD
        def_bool y
        depends on DYNAMIC_FTRACE
@@ -385,7 +446,7 @@ config FTRACE_SELFTEST
 
 config FTRACE_STARTUP_TEST
        bool "Perform a startup test on ftrace"
-       depends on TRACING
+       depends on GENERIC_TRACER
        select FTRACE_SELFTEST
        help
          This option performs a series of startup tests on ftrace. On bootup
@@ -396,7 +457,7 @@ config FTRACE_STARTUP_TEST
 config MMIOTRACE
        bool "Memory mapped IO tracing"
        depends on HAVE_MMIOTRACE_SUPPORT && PCI
-       select TRACING
+       select GENERIC_TRACER
        help
          Mmiotrace traces Memory Mapped I/O access and is meant for
          debugging and reverse engineering. It is called from the ioremap
@@ -416,7 +477,23 @@ config MMIOTRACE_TEST
 
          Say N, unless you absolutely know what you are doing.
 
-endmenu
+config RING_BUFFER_BENCHMARK
+       tristate "Ring buffer benchmark stress tester"
+       depends on RING_BUFFER
+       help
+         This option creates a test to stress the ring buffer and bench mark it.
+         It creates its own ring buffer such that it will not interfer with
+         any other users of the ring buffer (such as ftrace). It then creates
+         a producer and consumer that will run for 10 seconds and sleep for
+         10 seconds. Each interval it will print out the number of events
+         it recorded and give a rough estimate of how long each iteration took.
+
+         It does not disable interrupts or raise its priority, so it may be
+         affected by processes that are running.
+
+         If unsure, say N
+
+endif # FTRACE
 
 endif # TRACING_SUPPORT
 
index 2630f5121ec12467a4b05958670aac40f357dcb8..844164dca90ae1ec9039ccfd66c5a89aaa8d1a3d 100644 (file)
@@ -15,11 +15,17 @@ ifdef CONFIG_TRACING_BRANCHES
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
 endif
 
+#
+# Make the trace clocks available generally: it's infrastructure
+# relied on by ptrace for example:
+#
+obj-y += trace_clock.o
+
 obj-$(CONFIG_FUNCTION_TRACER) += libftrace.o
 obj-$(CONFIG_RING_BUFFER) += ring_buffer.o
+obj-$(CONFIG_RING_BUFFER_BENCHMARK) += ring_buffer_benchmark.o
 
 obj-$(CONFIG_TRACING) += trace.o
-obj-$(CONFIG_TRACING) += trace_clock.o
 obj-$(CONFIG_TRACING) += trace_output.o
 obj-$(CONFIG_TRACING) += trace_stat.o
 obj-$(CONFIG_TRACING) += trace_printk.o
@@ -39,12 +45,14 @@ obj-$(CONFIG_HW_BRANCH_TRACER) += trace_hw_branches.o
 obj-$(CONFIG_POWER_TRACER) += trace_power.o
 obj-$(CONFIG_KMEMTRACE) += kmemtrace.o
 obj-$(CONFIG_WORKQUEUE_TRACER) += trace_workqueue.o
-obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
-obj-$(CONFIG_EVENT_TRACER) += trace_events.o
-obj-$(CONFIG_EVENT_TRACER) += events.o
-obj-$(CONFIG_EVENT_TRACER) += trace_export.o
+obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
+ifeq ($(CONFIG_BLOCK),y)
+obj-$(CONFIG_EVENT_TRACING) += blktrace.o
+endif
+obj-$(CONFIG_EVENT_TRACING) += trace_events.o
+obj-$(CONFIG_EVENT_TRACING) += trace_export.o
 obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o
 obj-$(CONFIG_EVENT_PROFILE) += trace_event_profile.o
-obj-$(CONFIG_EVENT_TRACER) += trace_events_filter.o
+obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
 
 libftrace-y := ftrace.o
index 921ef5d1f0ba95e7497faa55afb293c50ae7ee47..39af8af6fc302c981226ab8c8f277026b319ca4a 100644 (file)
 #include <linux/mutex.h>
 #include <linux/debugfs.h>
 #include <linux/time.h>
-#include <trace/block.h>
 #include <linux/uaccess.h>
+
+#include <trace/events/block.h>
+
 #include "trace_output.h"
 
+#ifdef CONFIG_BLK_DEV_IO_TRACE
+
 static unsigned int blktrace_seq __read_mostly = 1;
 
 static struct trace_array *blk_tr;
@@ -147,7 +151,7 @@ static int act_log_check(struct blk_trace *bt, u32 what, sector_t sector,
 {
        if (((bt->act_mask << BLK_TC_SHIFT) & what) == 0)
                return 1;
-       if (sector < bt->start_lba || sector > bt->end_lba)
+       if (sector && (sector < bt->start_lba || sector > bt->end_lba))
                return 1;
        if (bt->pid && pid != bt->pid)
                return 1;
@@ -192,7 +196,7 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
        what |= MASK_TC_BIT(rw, DISCARD);
 
        pid = tsk->pid;
-       if (unlikely(act_log_check(bt, what, sector, pid)))
+       if (act_log_check(bt, what, sector, pid))
                return;
        cpu = raw_smp_processor_id();
 
@@ -262,6 +266,7 @@ static void blk_trace_free(struct blk_trace *bt)
 {
        debugfs_remove(bt->msg_file);
        debugfs_remove(bt->dropped_file);
+       debugfs_remove(bt->dir);
        relay_close(bt->rchan);
        free_percpu(bt->sequence);
        free_percpu(bt->msg_data);
@@ -403,11 +408,29 @@ static struct rchan_callbacks blk_relay_callbacks = {
        .remove_buf_file        = blk_remove_buf_file_callback,
 };
 
+static void blk_trace_setup_lba(struct blk_trace *bt,
+                               struct block_device *bdev)
+{
+       struct hd_struct *part = NULL;
+
+       if (bdev)
+               part = bdev->bd_part;
+
+       if (part) {
+               bt->start_lba = part->start_sect;
+               bt->end_lba = part->start_sect + part->nr_sects;
+       } else {
+               bt->start_lba = 0;
+               bt->end_lba = -1ULL;
+       }
+}
+
 /*
  * Setup everything required to start tracing
  */
 int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
-                       struct blk_user_trace_setup *buts)
+                      struct block_device *bdev,
+                      struct blk_user_trace_setup *buts)
 {
        struct blk_trace *old_bt, *bt = NULL;
        struct dentry *dir = NULL;
@@ -480,10 +503,13 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
        if (!bt->act_mask)
                bt->act_mask = (u16) -1;
 
-       bt->start_lba = buts->start_lba;
-       bt->end_lba = buts->end_lba;
-       if (!bt->end_lba)
-               bt->end_lba = -1ULL;
+       blk_trace_setup_lba(bt, bdev);
+
+       /* overwrite with user settings */
+       if (buts->start_lba)
+               bt->start_lba = buts->start_lba;
+       if (buts->end_lba)
+               bt->end_lba = buts->end_lba;
 
        bt->pid = buts->pid;
        bt->trace_state = Blktrace_setup;
@@ -505,6 +531,7 @@ err:
 }
 
 int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
+                   struct block_device *bdev,
                    char __user *arg)
 {
        struct blk_user_trace_setup buts;
@@ -514,7 +541,7 @@ int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
        if (ret)
                return -EFAULT;
 
-       ret = do_blk_trace_setup(q, name, dev, &buts);
+       ret = do_blk_trace_setup(q, name, dev, bdev, &buts);
        if (ret)
                return ret;
 
@@ -582,7 +609,7 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
        switch (cmd) {
        case BLKTRACESETUP:
                bdevname(bdev, b);
-               ret = blk_trace_setup(q, b, bdev->bd_dev, arg);
+               ret = blk_trace_setup(q, b, bdev->bd_dev, bdev, arg);
                break;
        case BLKTRACESTART:
                start = 1;
@@ -642,12 +669,12 @@ static void blk_add_trace_rq(struct request_queue *q, struct request *rq,
 
        if (blk_pc_request(rq)) {
                what |= BLK_TC_ACT(BLK_TC_PC);
-               __blk_add_trace(bt, 0, rq->data_len, rw, what, rq->errors,
-                               rq->cmd_len, rq->cmd);
+               __blk_add_trace(bt, 0, blk_rq_bytes(rq), rw,
+                               what, rq->errors, rq->cmd_len, rq->cmd);
        } else  {
                what |= BLK_TC_ACT(BLK_TC_FS);
-               __blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9,
-                               rw, what, rq->errors, 0, NULL);
+               __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), rw,
+                               what, rq->errors, 0, NULL);
        }
 }
 
@@ -809,7 +836,6 @@ static void blk_add_trace_split(struct request_queue *q, struct bio *bio,
  * @bio:       the source bio
  * @dev:       target device
  * @from:      source sector
- * @to:                target sector
  *
  * Description:
  *     Device mapper or raid target sometimes need to split a bio because
@@ -817,7 +843,7 @@ static void blk_add_trace_split(struct request_queue *q, struct bio *bio,
  *
  **/
 static void blk_add_trace_remap(struct request_queue *q, struct bio *bio,
-                                      dev_t dev, sector_t from, sector_t to)
+                                      dev_t dev, sector_t from)
 {
        struct blk_trace *bt = q->blk_trace;
        struct blk_io_trace_remap r;
@@ -825,12 +851,13 @@ static void blk_add_trace_remap(struct request_queue *q, struct bio *bio,
        if (likely(!bt))
                return;
 
-       r.device = cpu_to_be32(dev);
-       r.device_from = cpu_to_be32(bio->bi_bdev->bd_dev);
-       r.sector = cpu_to_be64(to);
+       r.device_from = cpu_to_be32(dev);
+       r.device_to   = cpu_to_be32(bio->bi_bdev->bd_dev);
+       r.sector_from = cpu_to_be64(from);
 
-       __blk_add_trace(bt, from, bio->bi_size, bio->bi_rw, BLK_TA_REMAP,
-                       !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r);
+       __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw,
+                       BLK_TA_REMAP, !bio_flagged(bio, BIO_UPTODATE),
+                       sizeof(r), &r);
 }
 
 /**
@@ -854,11 +881,11 @@ void blk_add_driver_data(struct request_queue *q,
                return;
 
        if (blk_pc_request(rq))
-               __blk_add_trace(bt, 0, rq->data_len, 0, BLK_TA_DRV_DATA,
-                               rq->errors, len, data);
+               __blk_add_trace(bt, 0, blk_rq_bytes(rq), 0,
+                               BLK_TA_DRV_DATA, rq->errors, len, data);
        else
-               __blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9,
-                               0, BLK_TA_DRV_DATA, rq->errors, len, data);
+               __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), 0,
+                               BLK_TA_DRV_DATA, rq->errors, len, data);
 }
 EXPORT_SYMBOL_GPL(blk_add_driver_data);
 
@@ -971,6 +998,16 @@ static inline const void *pdu_start(const struct trace_entry *ent)
        return te_blk_io_trace(ent) + 1;
 }
 
+static inline u32 t_action(const struct trace_entry *ent)
+{
+       return te_blk_io_trace(ent)->action;
+}
+
+static inline u32 t_bytes(const struct trace_entry *ent)
+{
+       return te_blk_io_trace(ent)->bytes;
+}
+
 static inline u32 t_sec(const struct trace_entry *ent)
 {
        return te_blk_io_trace(ent)->bytes >> 9;
@@ -996,11 +1033,11 @@ static void get_pdu_remap(const struct trace_entry *ent,
                          struct blk_io_trace_remap *r)
 {
        const struct blk_io_trace_remap *__r = pdu_start(ent);
-       __u64 sector = __r->sector;
+       __u64 sector_from = __r->sector_from;
 
-       r->device = be32_to_cpu(__r->device);
        r->device_from = be32_to_cpu(__r->device_from);
-       r->sector = be64_to_cpu(sector);
+       r->device_to   = be32_to_cpu(__r->device_to);
+       r->sector_from = be64_to_cpu(sector_from);
 }
 
 typedef int (blk_log_action_t) (struct trace_iterator *iter, const char *act);
@@ -1031,36 +1068,98 @@ static int blk_log_action(struct trace_iterator *iter, const char *act)
                                MAJOR(t->device), MINOR(t->device), act, rwbs);
 }
 
+static int blk_log_dump_pdu(struct trace_seq *s, const struct trace_entry *ent)
+{
+       const unsigned char *pdu_buf;
+       int pdu_len;
+       int i, end, ret;
+
+       pdu_buf = pdu_start(ent);
+       pdu_len = te_blk_io_trace(ent)->pdu_len;
+
+       if (!pdu_len)
+               return 1;
+
+       /* find the last zero that needs to be printed */
+       for (end = pdu_len - 1; end >= 0; end--)
+               if (pdu_buf[end])
+                       break;
+       end++;
+
+       if (!trace_seq_putc(s, '('))
+               return 0;
+
+       for (i = 0; i < pdu_len; i++) {
+
+               ret = trace_seq_printf(s, "%s%02x",
+                                      i == 0 ? "" : " ", pdu_buf[i]);
+               if (!ret)
+                       return ret;
+
+               /*
+                * stop when the rest is just zeroes and indicate so
+                * with a ".." appended
+                */
+               if (i == end && end != pdu_len - 1)
+                       return trace_seq_puts(s, " ..) ");
+       }
+
+       return trace_seq_puts(s, ") ");
+}
+
 static int blk_log_generic(struct trace_seq *s, const struct trace_entry *ent)
 {
        char cmd[TASK_COMM_LEN];
 
        trace_find_cmdline(ent->pid, cmd);
 
-       if (t_sec(ent))
-               return trace_seq_printf(s, "%llu + %u [%s]\n",
-                                       t_sector(ent), t_sec(ent), cmd);
-       return trace_seq_printf(s, "[%s]\n", cmd);
+       if (t_action(ent) & BLK_TC_ACT(BLK_TC_PC)) {
+               int ret;
+
+               ret = trace_seq_printf(s, "%u ", t_bytes(ent));
+               if (!ret)
+                       return 0;
+               ret = blk_log_dump_pdu(s, ent);
+               if (!ret)
+                       return 0;
+               return trace_seq_printf(s, "[%s]\n", cmd);
+       } else {
+               if (t_sec(ent))
+                       return trace_seq_printf(s, "%llu + %u [%s]\n",
+                                               t_sector(ent), t_sec(ent), cmd);
+               return trace_seq_printf(s, "[%s]\n", cmd);
+       }
 }
 
 static int blk_log_with_error(struct trace_seq *s,
                              const struct trace_entry *ent)
 {
-       if (t_sec(ent))
-               return trace_seq_printf(s, "%llu + %u [%d]\n", t_sector(ent),
-                                       t_sec(ent), t_error(ent));
-       return trace_seq_printf(s, "%llu [%d]\n", t_sector(ent), t_error(ent));
+       if (t_action(ent) & BLK_TC_ACT(BLK_TC_PC)) {
+               int ret;
+
+               ret = blk_log_dump_pdu(s, ent);
+               if (ret)
+                       return trace_seq_printf(s, "[%d]\n", t_error(ent));
+               return 0;
+       } else {
+               if (t_sec(ent))
+                       return trace_seq_printf(s, "%llu + %u [%d]\n",
+                                               t_sector(ent),
+                                               t_sec(ent), t_error(ent));
+               return trace_seq_printf(s, "%llu [%d]\n",
+                                       t_sector(ent), t_error(ent));
+       }
 }
 
 static int blk_log_remap(struct trace_seq *s, const struct trace_entry *ent)
 {
-       struct blk_io_trace_remap r = { .device = 0, };
+       struct blk_io_trace_remap r = { .device_from = 0, };
 
        get_pdu_remap(ent, &r);
        return trace_seq_printf(s, "%llu + %u <- (%d,%d) %llu\n",
-                              t_sector(ent),
-                              t_sec(ent), MAJOR(r.device), MINOR(r.device),
-                              (unsigned long long)r.sector);
+                               t_sector(ent), t_sec(ent),
+                               MAJOR(r.device_from), MINOR(r.device_from),
+                               (unsigned long long)r.sector_from);
 }
 
 static int blk_log_plug(struct trace_seq *s, const struct trace_entry *ent)
@@ -1117,7 +1216,6 @@ static void blk_tracer_print_header(struct seq_file *m)
 static void blk_tracer_start(struct trace_array *tr)
 {
        blk_tracer_enabled = true;
-       trace_flags &= ~TRACE_ITER_CONTEXT_INFO;
 }
 
 static int blk_tracer_init(struct trace_array *tr)
@@ -1130,7 +1228,6 @@ static int blk_tracer_init(struct trace_array *tr)
 static void blk_tracer_stop(struct trace_array *tr)
 {
        blk_tracer_enabled = false;
-       trace_flags |= TRACE_ITER_CONTEXT_INFO;
 }
 
 static void blk_tracer_reset(struct trace_array *tr)
@@ -1182,7 +1279,7 @@ static enum print_line_t print_one_line(struct trace_iterator *iter,
        }
 
        if (unlikely(what == 0 || what >= ARRAY_SIZE(what2act)))
-               ret = trace_seq_printf(s, "Bad pc action %x\n", what);
+               ret = trace_seq_printf(s, "Unknown action %x\n", what);
        else {
                ret = log_action(iter, what2act[what].act[long_act]);
                if (ret)
@@ -1195,9 +1292,6 @@ out:
 static enum print_line_t blk_trace_event_print(struct trace_iterator *iter,
                                               int flags)
 {
-       if (!trace_print_context(iter))
-               return TRACE_TYPE_PARTIAL_LINE;
-
        return print_one_line(iter, false);
 }
 
@@ -1232,6 +1326,18 @@ static enum print_line_t blk_tracer_print_line(struct trace_iterator *iter)
        return print_one_line(iter, true);
 }
 
+static int blk_tracer_set_flag(u32 old_flags, u32 bit, int set)
+{
+       /* don't output context-info for blk_classic output */
+       if (bit == TRACE_BLK_OPT_CLASSIC) {
+               if (set)
+                       trace_flags &= ~TRACE_ITER_CONTEXT_INFO;
+               else
+                       trace_flags |= TRACE_ITER_CONTEXT_INFO;
+       }
+       return 0;
+}
+
 static struct tracer blk_tracer __read_mostly = {
        .name           = "blk",
        .init           = blk_tracer_init,
@@ -1241,6 +1347,7 @@ static struct tracer blk_tracer __read_mostly = {
        .print_header   = blk_tracer_print_header,
        .print_line     = blk_tracer_print_line,
        .flags          = &blk_tracer_flags,
+       .set_flag       = blk_tracer_set_flag,
 };
 
 static struct trace_event trace_blk_event = {
@@ -1285,7 +1392,8 @@ static int blk_trace_remove_queue(struct request_queue *q)
 /*
  * Setup everything required to start tracing
  */
-static int blk_trace_setup_queue(struct request_queue *q, dev_t dev)
+static int blk_trace_setup_queue(struct request_queue *q,
+                                struct block_device *bdev)
 {
        struct blk_trace *old_bt, *bt = NULL;
        int ret = -ENOMEM;
@@ -1298,9 +1406,10 @@ static int blk_trace_setup_queue(struct request_queue *q, dev_t dev)
        if (!bt->msg_data)
                goto free_bt;
 
-       bt->dev = dev;
+       bt->dev = bdev->bd_dev;
        bt->act_mask = (u16)-1;
-       bt->end_lba = -1ULL;
+
+       blk_trace_setup_lba(bt, bdev);
 
        old_bt = xchg(&q->blk_trace, bt);
        if (old_bt != NULL) {
@@ -1517,7 +1626,7 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev,
 
        if (attr == &dev_attr_enable) {
                if (value)
-                       ret = blk_trace_setup_queue(q, bdev->bd_dev);
+                       ret = blk_trace_setup_queue(q, bdev);
                else
                        ret = blk_trace_remove_queue(q);
                goto out_unlock_bdev;
@@ -1525,7 +1634,7 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev,
 
        ret = 0;
        if (q->blk_trace == NULL)
-               ret = blk_trace_setup_queue(q, bdev->bd_dev);
+               ret = blk_trace_setup_queue(q, bdev);
 
        if (ret == 0) {
                if (attr == &dev_attr_act_mask)
@@ -1548,3 +1657,77 @@ out:
        return ret ? ret : count;
 }
 
+int blk_trace_init_sysfs(struct device *dev)
+{
+       return sysfs_create_group(&dev->kobj, &blk_trace_attr_group);
+}
+
+#endif /* CONFIG_BLK_DEV_IO_TRACE */
+
+#ifdef CONFIG_EVENT_TRACING
+
+void blk_dump_cmd(char *buf, struct request *rq)
+{
+       int i, end;
+       int len = rq->cmd_len;
+       unsigned char *cmd = rq->cmd;
+
+       if (!blk_pc_request(rq)) {
+               buf[0] = '\0';
+               return;
+       }
+
+       for (end = len - 1; end >= 0; end--)
+               if (cmd[end])
+                       break;
+       end++;
+
+       for (i = 0; i < len; i++) {
+               buf += sprintf(buf, "%s%02x", i == 0 ? "" : " ", cmd[i]);
+               if (i == end && end != len - 1) {
+                       sprintf(buf, " ..");
+                       break;
+               }
+       }
+}
+
+void blk_fill_rwbs(char *rwbs, u32 rw, int bytes)
+{
+       int i = 0;
+
+       if (rw & WRITE)
+               rwbs[i++] = 'W';
+       else if (rw & 1 << BIO_RW_DISCARD)
+               rwbs[i++] = 'D';
+       else if (bytes)
+               rwbs[i++] = 'R';
+       else
+               rwbs[i++] = 'N';
+
+       if (rw & 1 << BIO_RW_AHEAD)
+               rwbs[i++] = 'A';
+       if (rw & 1 << BIO_RW_BARRIER)
+               rwbs[i++] = 'B';
+       if (rw & 1 << BIO_RW_SYNCIO)
+               rwbs[i++] = 'S';
+       if (rw & 1 << BIO_RW_META)
+               rwbs[i++] = 'M';
+
+       rwbs[i] = '\0';
+}
+
+void blk_fill_rwbs_rq(char *rwbs, struct request *rq)
+{
+       int rw = rq->cmd_flags & 0x03;
+       int bytes;
+
+       if (blk_discard_rq(rq))
+               rw |= (1 << BIO_RW_DISCARD);
+
+       bytes = blk_rq_bytes(rq);
+
+       blk_fill_rwbs(rwbs, rw, bytes);
+}
+
+#endif /* CONFIG_EVENT_TRACING */
+
diff --git a/kernel/trace/events.c b/kernel/trace/events.c
deleted file mode 100644 (file)
index 246f2aa..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * This is the place to register all trace points as events.
- */
-
-#include <linux/stringify.h>
-
-#include <trace/trace_events.h>
-
-#include "trace_output.h"
-
-#include "trace_events_stage_1.h"
-#include "trace_events_stage_2.h"
-#include "trace_events_stage_3.h"
-
index f1ed080406c31f6bf61025e34e626f71b2865ad6..bb60732ade0cc7bca54fdbff32a9dfda16bacde9 100644 (file)
 #include <linux/list.h>
 #include <linux/hash.h>
 
-#include <trace/sched.h>
+#include <trace/events/sched.h>
 
 #include <asm/ftrace.h>
+#include <asm/setup.h>
 
-#include "trace.h"
+#include "trace_output.h"
+#include "trace_stat.h"
 
 #define FTRACE_WARN_ON(cond)                   \
        do {                                    \
@@ -68,7 +70,7 @@ static DEFINE_MUTEX(ftrace_lock);
 
 static struct ftrace_ops ftrace_list_end __read_mostly =
 {
-       .func = ftrace_stub,
+       .func           = ftrace_stub,
 };
 
 static struct ftrace_ops *ftrace_list __read_mostly = &ftrace_list_end;
@@ -240,6 +242,580 @@ static void ftrace_update_pid_func(void)
 #endif
 }
 
+#ifdef CONFIG_FUNCTION_PROFILER
+struct ftrace_profile {
+       struct hlist_node               node;
+       unsigned long                   ip;
+       unsigned long                   counter;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       unsigned long long              time;
+#endif
+};
+
+struct ftrace_profile_page {
+       struct ftrace_profile_page      *next;
+       unsigned long                   index;
+       struct ftrace_profile           records[];
+};
+
+struct ftrace_profile_stat {
+       atomic_t                        disabled;
+       struct hlist_head               *hash;
+       struct ftrace_profile_page      *pages;
+       struct ftrace_profile_page      *start;
+       struct tracer_stat              stat;
+};
+
+#define PROFILE_RECORDS_SIZE                                           \
+       (PAGE_SIZE - offsetof(struct ftrace_profile_page, records))
+
+#define PROFILES_PER_PAGE                                      \
+       (PROFILE_RECORDS_SIZE / sizeof(struct ftrace_profile))
+
+static int ftrace_profile_bits __read_mostly;
+static int ftrace_profile_enabled __read_mostly;
+
+/* ftrace_profile_lock - synchronize the enable and disable of the profiler */
+static DEFINE_MUTEX(ftrace_profile_lock);
+
+static DEFINE_PER_CPU(struct ftrace_profile_stat, ftrace_profile_stats);
+
+#define FTRACE_PROFILE_HASH_SIZE 1024 /* must be power of 2 */
+
+static void *
+function_stat_next(void *v, int idx)
+{
+       struct ftrace_profile *rec = v;
+       struct ftrace_profile_page *pg;
+
+       pg = (struct ftrace_profile_page *)((unsigned long)rec & PAGE_MASK);
+
+ again:
+       rec++;
+       if ((void *)rec >= (void *)&pg->records[pg->index]) {
+               pg = pg->next;
+               if (!pg)
+                       return NULL;
+               rec = &pg->records[0];
+               if (!rec->counter)
+                       goto again;
+       }
+
+       return rec;
+}
+
+static void *function_stat_start(struct tracer_stat *trace)
+{
+       struct ftrace_profile_stat *stat =
+               container_of(trace, struct ftrace_profile_stat, stat);
+
+       if (!stat || !stat->start)
+               return NULL;
+
+       return function_stat_next(&stat->start->records[0], 0);
+}
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+/* function graph compares on total time */
+static int function_stat_cmp(void *p1, void *p2)
+{
+       struct ftrace_profile *a = p1;
+       struct ftrace_profile *b = p2;
+
+       if (a->time < b->time)
+               return -1;
+       if (a->time > b->time)
+               return 1;
+       else
+               return 0;
+}
+#else
+/* not function graph compares against hits */
+static int function_stat_cmp(void *p1, void *p2)
+{
+       struct ftrace_profile *a = p1;
+       struct ftrace_profile *b = p2;
+
+       if (a->counter < b->counter)
+               return -1;
+       if (a->counter > b->counter)
+               return 1;
+       else
+               return 0;
+}
+#endif
+
+static int function_stat_headers(struct seq_file *m)
+{
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       seq_printf(m, "  Function                               "
+                  "Hit    Time            Avg\n"
+                     "  --------                               "
+                  "---    ----            ---\n");
+#else
+       seq_printf(m, "  Function                               Hit\n"
+                     "  --------                               ---\n");
+#endif
+       return 0;
+}
+
+static int function_stat_show(struct seq_file *m, void *v)
+{
+       struct ftrace_profile *rec = v;
+       char str[KSYM_SYMBOL_LEN];
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       static DEFINE_MUTEX(mutex);
+       static struct trace_seq s;
+       unsigned long long avg;
+#endif
+
+       kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
+       seq_printf(m, "  %-30.30s  %10lu", str, rec->counter);
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       seq_printf(m, "    ");
+       avg = rec->time;
+       do_div(avg, rec->counter);
+
+       mutex_lock(&mutex);
+       trace_seq_init(&s);
+       trace_print_graph_duration(rec->time, &s);
+       trace_seq_puts(&s, "    ");
+       trace_print_graph_duration(avg, &s);
+       trace_print_seq(m, &s);
+       mutex_unlock(&mutex);
+#endif
+       seq_putc(m, '\n');
+
+       return 0;
+}
+
+static void ftrace_profile_reset(struct ftrace_profile_stat *stat)
+{
+       struct ftrace_profile_page *pg;
+
+       pg = stat->pages = stat->start;
+
+       while (pg) {
+               memset(pg->records, 0, PROFILE_RECORDS_SIZE);
+               pg->index = 0;
+               pg = pg->next;
+       }
+
+       memset(stat->hash, 0,
+              FTRACE_PROFILE_HASH_SIZE * sizeof(struct hlist_head));
+}
+
+int ftrace_profile_pages_init(struct ftrace_profile_stat *stat)
+{
+       struct ftrace_profile_page *pg;
+       int functions;
+       int pages;
+       int i;
+
+       /* If we already allocated, do nothing */
+       if (stat->pages)
+               return 0;
+
+       stat->pages = (void *)get_zeroed_page(GFP_KERNEL);
+       if (!stat->pages)
+               return -ENOMEM;
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+       functions = ftrace_update_tot_cnt;
+#else
+       /*
+        * We do not know the number of functions that exist because
+        * dynamic tracing is what counts them. With past experience
+        * we have around 20K functions. That should be more than enough.
+        * It is highly unlikely we will execute every function in
+        * the kernel.
+        */
+       functions = 20000;
+#endif
+
+       pg = stat->start = stat->pages;
+
+       pages = DIV_ROUND_UP(functions, PROFILES_PER_PAGE);
+
+       for (i = 0; i < pages; i++) {
+               pg->next = (void *)get_zeroed_page(GFP_KERNEL);
+               if (!pg->next)
+                       goto out_free;
+               pg = pg->next;
+       }
+
+       return 0;
+
+ out_free:
+       pg = stat->start;
+       while (pg) {
+               unsigned long tmp = (unsigned long)pg;
+
+               pg = pg->next;
+               free_page(tmp);
+       }
+
+       free_page((unsigned long)stat->pages);
+       stat->pages = NULL;
+       stat->start = NULL;
+
+       return -ENOMEM;
+}
+
+static int ftrace_profile_init_cpu(int cpu)
+{
+       struct ftrace_profile_stat *stat;
+       int size;
+
+       stat = &per_cpu(ftrace_profile_stats, cpu);
+
+       if (stat->hash) {
+               /* If the profile is already created, simply reset it */
+               ftrace_profile_reset(stat);
+               return 0;
+       }
+
+       /*
+        * We are profiling all functions, but usually only a few thousand
+        * functions are hit. We'll make a hash of 1024 items.
+        */
+       size = FTRACE_PROFILE_HASH_SIZE;
+
+       stat->hash = kzalloc(sizeof(struct hlist_head) * size, GFP_KERNEL);
+
+       if (!stat->hash)
+               return -ENOMEM;
+
+       if (!ftrace_profile_bits) {
+               size--;
+
+               for (; size; size >>= 1)
+                       ftrace_profile_bits++;
+       }
+
+       /* Preallocate the function profiling pages */
+       if (ftrace_profile_pages_init(stat) < 0) {
+               kfree(stat->hash);
+               stat->hash = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int ftrace_profile_init(void)
+{
+       int cpu;
+       int ret = 0;
+
+       for_each_online_cpu(cpu) {
+               ret = ftrace_profile_init_cpu(cpu);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+/* interrupts must be disabled */
+static struct ftrace_profile *
+ftrace_find_profiled_func(struct ftrace_profile_stat *stat, unsigned long ip)
+{
+       struct ftrace_profile *rec;
+       struct hlist_head *hhd;
+       struct hlist_node *n;
+       unsigned long key;
+
+       key = hash_long(ip, ftrace_profile_bits);
+       hhd = &stat->hash[key];
+
+       if (hlist_empty(hhd))
+               return NULL;
+
+       hlist_for_each_entry_rcu(rec, n, hhd, node) {
+               if (rec->ip == ip)
+                       return rec;
+       }
+
+       return NULL;
+}
+
+static void ftrace_add_profile(struct ftrace_profile_stat *stat,
+                              struct ftrace_profile *rec)
+{
+       unsigned long key;
+
+       key = hash_long(rec->ip, ftrace_profile_bits);
+       hlist_add_head_rcu(&rec->node, &stat->hash[key]);
+}
+
+/*
+ * The memory is already allocated, this simply finds a new record to use.
+ */
+static struct ftrace_profile *
+ftrace_profile_alloc(struct ftrace_profile_stat *stat, unsigned long ip)
+{
+       struct ftrace_profile *rec = NULL;
+
+       /* prevent recursion (from NMIs) */
+       if (atomic_inc_return(&stat->disabled) != 1)
+               goto out;
+
+       /*
+        * Try to find the function again since an NMI
+        * could have added it
+        */
+       rec = ftrace_find_profiled_func(stat, ip);
+       if (rec)
+               goto out;
+
+       if (stat->pages->index == PROFILES_PER_PAGE) {
+               if (!stat->pages->next)
+                       goto out;
+               stat->pages = stat->pages->next;
+       }
+
+       rec = &stat->pages->records[stat->pages->index++];
+       rec->ip = ip;
+       ftrace_add_profile(stat, rec);
+
+ out:
+       atomic_dec(&stat->disabled);
+
+       return rec;
+}
+
+static void
+function_profile_call(unsigned long ip, unsigned long parent_ip)
+{
+       struct ftrace_profile_stat *stat;
+       struct ftrace_profile *rec;
+       unsigned long flags;
+
+       if (!ftrace_profile_enabled)
+               return;
+
+       local_irq_save(flags);
+
+       stat = &__get_cpu_var(ftrace_profile_stats);
+       if (!stat->hash || !ftrace_profile_enabled)
+               goto out;
+
+       rec = ftrace_find_profiled_func(stat, ip);
+       if (!rec) {
+               rec = ftrace_profile_alloc(stat, ip);
+               if (!rec)
+                       goto out;
+       }
+
+       rec->counter++;
+ out:
+       local_irq_restore(flags);
+}
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+static int profile_graph_entry(struct ftrace_graph_ent *trace)
+{
+       function_profile_call(trace->func, 0);
+       return 1;
+}
+
+static void profile_graph_return(struct ftrace_graph_ret *trace)
+{
+       struct ftrace_profile_stat *stat;
+       unsigned long long calltime;
+       struct ftrace_profile *rec;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       stat = &__get_cpu_var(ftrace_profile_stats);
+       if (!stat->hash || !ftrace_profile_enabled)
+               goto out;
+
+       calltime = trace->rettime - trace->calltime;
+
+       if (!(trace_flags & TRACE_ITER_GRAPH_TIME)) {
+               int index;
+
+               index = trace->depth;
+
+               /* Append this call time to the parent time to subtract */
+               if (index)
+                       current->ret_stack[index - 1].subtime += calltime;
+
+               if (current->ret_stack[index].subtime < calltime)
+                       calltime -= current->ret_stack[index].subtime;
+               else
+                       calltime = 0;
+       }
+
+       rec = ftrace_find_profiled_func(stat, trace->func);
+       if (rec)
+               rec->time += calltime;
+
+ out:
+       local_irq_restore(flags);
+}
+
+static int register_ftrace_profiler(void)
+{
+       return register_ftrace_graph(&profile_graph_return,
+                                    &profile_graph_entry);
+}
+
+static void unregister_ftrace_profiler(void)
+{
+       unregister_ftrace_graph();
+}
+#else
+static struct ftrace_ops ftrace_profile_ops __read_mostly =
+{
+       .func           = function_profile_call,
+};
+
+static int register_ftrace_profiler(void)
+{
+       return register_ftrace_function(&ftrace_profile_ops);
+}
+
+static void unregister_ftrace_profiler(void)
+{
+       unregister_ftrace_function(&ftrace_profile_ops);
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+static ssize_t
+ftrace_profile_write(struct file *filp, const char __user *ubuf,
+                    size_t cnt, loff_t *ppos)
+{
+       unsigned long val;
+       char buf[64];           /* big enough to hold a number */
+       int ret;
+
+       if (cnt >= sizeof(buf))
+               return -EINVAL;
+
+       if (copy_from_user(&buf, ubuf, cnt))
+               return -EFAULT;
+
+       buf[cnt] = 0;
+
+       ret = strict_strtoul(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       val = !!val;
+
+       mutex_lock(&ftrace_profile_lock);
+       if (ftrace_profile_enabled ^ val) {
+               if (val) {
+                       ret = ftrace_profile_init();
+                       if (ret < 0) {
+                               cnt = ret;
+                               goto out;
+                       }
+
+                       ret = register_ftrace_profiler();
+                       if (ret < 0) {
+                               cnt = ret;
+                               goto out;
+                       }
+                       ftrace_profile_enabled = 1;
+               } else {
+                       ftrace_profile_enabled = 0;
+                       /*
+                        * unregister_ftrace_profiler calls stop_machine
+                        * so this acts like an synchronize_sched.
+                        */
+                       unregister_ftrace_profiler();
+               }
+       }
+ out:
+       mutex_unlock(&ftrace_profile_lock);
+
+       filp->f_pos += cnt;
+
+       return cnt;
+}
+
+static ssize_t
+ftrace_profile_read(struct file *filp, char __user *ubuf,
+                    size_t cnt, loff_t *ppos)
+{
+       char buf[64];           /* big enough to hold a number */
+       int r;
+
+       r = sprintf(buf, "%u\n", ftrace_profile_enabled);
+       return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+}
+
+static const struct file_operations ftrace_profile_fops = {
+       .open           = tracing_open_generic,
+       .read           = ftrace_profile_read,
+       .write          = ftrace_profile_write,
+};
+
+/* used to initialize the real stat files */
+static struct tracer_stat function_stats __initdata = {
+       .name           = "functions",
+       .stat_start     = function_stat_start,
+       .stat_next      = function_stat_next,
+       .stat_cmp       = function_stat_cmp,
+       .stat_headers   = function_stat_headers,
+       .stat_show      = function_stat_show
+};
+
+static void ftrace_profile_debugfs(struct dentry *d_tracer)
+{
+       struct ftrace_profile_stat *stat;
+       struct dentry *entry;
+       char *name;
+       int ret;
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               stat = &per_cpu(ftrace_profile_stats, cpu);
+
+               /* allocate enough for function name + cpu number */
+               name = kmalloc(32, GFP_KERNEL);
+               if (!name) {
+                       /*
+                        * The files created are permanent, if something happens
+                        * we still do not free memory.
+                        */
+                       kfree(stat);
+                       WARN(1,
+                            "Could not allocate stat file for cpu %d\n",
+                            cpu);
+                       return;
+               }
+               stat->stat = function_stats;
+               snprintf(name, 32, "function%d", cpu);
+               stat->stat.name = name;
+               ret = register_stat_tracer(&stat->stat);
+               if (ret) {
+                       WARN(1,
+                            "Could not register function stat for cpu %d\n",
+                            cpu);
+                       kfree(name);
+                       return;
+               }
+       }
+
+       entry = debugfs_create_file("function_profile_enabled", 0644,
+                                   d_tracer, NULL, &ftrace_profile_fops);
+       if (!entry)
+               pr_warning("Could not create debugfs "
+                          "'function_profile_enabled' entry\n");
+}
+
+#else /* CONFIG_FUNCTION_PROFILER */
+static void ftrace_profile_debugfs(struct dentry *d_tracer)
+{
+}
+#endif /* CONFIG_FUNCTION_PROFILER */
+
 /* set when tracing only a pid */
 struct pid *ftrace_pid_trace;
 static struct pid * const ftrace_swapper_pid = &init_struct_pid;
@@ -261,7 +837,6 @@ struct ftrace_func_probe {
        struct rcu_head         rcu;
 };
 
-
 enum {
        FTRACE_ENABLE_CALLS             = (1 << 0),
        FTRACE_DISABLE_CALLS            = (1 << 1),
@@ -346,30 +921,6 @@ static void ftrace_free_rec(struct dyn_ftrace *rec)
        rec->flags |= FTRACE_FL_FREE;
 }
 
-void ftrace_release(void *start, unsigned long size)
-{
-       struct dyn_ftrace *rec;
-       struct ftrace_page *pg;
-       unsigned long s = (unsigned long)start;
-       unsigned long e = s + size;
-
-       if (ftrace_disabled || !start)
-               return;
-
-       mutex_lock(&ftrace_lock);
-       do_for_each_ftrace_rec(pg, rec) {
-               if ((rec->ip >= s) && (rec->ip < e)) {
-                       /*
-                        * rec->ip is changed in ftrace_free_rec()
-                        * It should not between s and e if record was freed.
-                        */
-                       FTRACE_WARN_ON(rec->flags & FTRACE_FL_FREE);
-                       ftrace_free_rec(rec);
-               }
-       } while_for_each_ftrace_rec();
-       mutex_unlock(&ftrace_lock);
-}
-
 static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
 {
        struct dyn_ftrace *rec;
@@ -1408,7 +1959,7 @@ function_trace_probe_call(unsigned long ip, unsigned long parent_ip)
 
 static struct ftrace_ops trace_probe_ops __read_mostly =
 {
-       .func = function_trace_probe_call,
+       .func           = function_trace_probe_call,
 };
 
 static int ftrace_probe_registered;
@@ -1823,6 +2374,45 @@ void ftrace_set_notrace(unsigned char *buf, int len, int reset)
        ftrace_set_regex(buf, len, reset, 0);
 }
 
+/*
+ * command line interface to allow users to set filters on boot up.
+ */
+#define FTRACE_FILTER_SIZE             COMMAND_LINE_SIZE
+static char ftrace_notrace_buf[FTRACE_FILTER_SIZE] __initdata;
+static char ftrace_filter_buf[FTRACE_FILTER_SIZE] __initdata;
+
+static int __init set_ftrace_notrace(char *str)
+{
+       strncpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE);
+       return 1;
+}
+__setup("ftrace_notrace=", set_ftrace_notrace);
+
+static int __init set_ftrace_filter(char *str)
+{
+       strncpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE);
+       return 1;
+}
+__setup("ftrace_filter=", set_ftrace_filter);
+
+static void __init set_ftrace_early_filter(char *buf, int enable)
+{
+       char *func;
+
+       while (buf) {
+               func = strsep(&buf, ",");
+               ftrace_set_regex(func, strlen(func), 0, enable);
+       }
+}
+
+static void __init set_ftrace_early_filters(void)
+{
+       if (ftrace_filter_buf[0])
+               set_ftrace_early_filter(ftrace_filter_buf, 1);
+       if (ftrace_notrace_buf[0])
+               set_ftrace_early_filter(ftrace_notrace_buf, 0);
+}
+
 static int
 ftrace_regex_release(struct inode *inode, struct file *file, int enable)
 {
@@ -2128,38 +2718,23 @@ static const struct file_operations ftrace_graph_fops = {
 
 static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer)
 {
-       struct dentry *entry;
 
-       entry = debugfs_create_file("available_filter_functions", 0444,
-                                   d_tracer, NULL, &ftrace_avail_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs "
-                          "'available_filter_functions' entry\n");
+       trace_create_file("available_filter_functions", 0444,
+                       d_tracer, NULL, &ftrace_avail_fops);
 
-       entry = debugfs_create_file("failures", 0444,
-                                   d_tracer, NULL, &ftrace_failures_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'failures' entry\n");
+       trace_create_file("failures", 0444,
+                       d_tracer, NULL, &ftrace_failures_fops);
 
-       entry = debugfs_create_file("set_ftrace_filter", 0644, d_tracer,
-                                   NULL, &ftrace_filter_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs "
-                          "'set_ftrace_filter' entry\n");
+       trace_create_file("set_ftrace_filter", 0644, d_tracer,
+                       NULL, &ftrace_filter_fops);
 
-       entry = debugfs_create_file("set_ftrace_notrace", 0644, d_tracer,
+       trace_create_file("set_ftrace_notrace", 0644, d_tracer,
                                    NULL, &ftrace_notrace_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs "
-                          "'set_ftrace_notrace' entry\n");
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
-       entry = debugfs_create_file("set_graph_function", 0444, d_tracer,
+       trace_create_file("set_graph_function", 0444, d_tracer,
                                    NULL,
                                    &ftrace_graph_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs "
-                          "'set_graph_function' entry\n");
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 
        return 0;
@@ -2197,14 +2772,72 @@ static int ftrace_convert_nops(struct module *mod,
        return 0;
 }
 
-void ftrace_init_module(struct module *mod,
-                       unsigned long *start, unsigned long *end)
+#ifdef CONFIG_MODULES
+void ftrace_release(void *start, void *end)
+{
+       struct dyn_ftrace *rec;
+       struct ftrace_page *pg;
+       unsigned long s = (unsigned long)start;
+       unsigned long e = (unsigned long)end;
+
+       if (ftrace_disabled || !start || start == end)
+               return;
+
+       mutex_lock(&ftrace_lock);
+       do_for_each_ftrace_rec(pg, rec) {
+               if ((rec->ip >= s) && (rec->ip < e)) {
+                       /*
+                        * rec->ip is changed in ftrace_free_rec()
+                        * It should not between s and e if record was freed.
+                        */
+                       FTRACE_WARN_ON(rec->flags & FTRACE_FL_FREE);
+                       ftrace_free_rec(rec);
+               }
+       } while_for_each_ftrace_rec();
+       mutex_unlock(&ftrace_lock);
+}
+
+static void ftrace_init_module(struct module *mod,
+                              unsigned long *start, unsigned long *end)
 {
        if (ftrace_disabled || start == end)
                return;
        ftrace_convert_nops(mod, start, end);
 }
 
+static int ftrace_module_notify(struct notifier_block *self,
+                               unsigned long val, void *data)
+{
+       struct module *mod = data;
+
+       switch (val) {
+       case MODULE_STATE_COMING:
+               ftrace_init_module(mod, mod->ftrace_callsites,
+                                  mod->ftrace_callsites +
+                                  mod->num_ftrace_callsites);
+               break;
+       case MODULE_STATE_GOING:
+               ftrace_release(mod->ftrace_callsites,
+                              mod->ftrace_callsites +
+                              mod->num_ftrace_callsites);
+               break;
+       }
+
+       return 0;
+}
+#else
+static int ftrace_module_notify(struct notifier_block *self,
+                               unsigned long val, void *data)
+{
+       return 0;
+}
+#endif /* CONFIG_MODULES */
+
+struct notifier_block ftrace_module_nb = {
+       .notifier_call = ftrace_module_notify,
+       .priority = 0,
+};
+
 extern unsigned long __start_mcount_loc[];
 extern unsigned long __stop_mcount_loc[];
 
@@ -2236,6 +2869,12 @@ void __init ftrace_init(void)
                                  __start_mcount_loc,
                                  __stop_mcount_loc);
 
+       ret = register_module_notifier(&ftrace_module_nb);
+       if (ret)
+               pr_warning("Failed to register trace ftrace module notifier\n");
+
+       set_ftrace_early_filters();
+
        return;
  failed:
        ftrace_disabled = 1;
@@ -2417,7 +3056,6 @@ static const struct file_operations ftrace_pid_fops = {
 static __init int ftrace_init_debugfs(void)
 {
        struct dentry *d_tracer;
-       struct dentry *entry;
 
        d_tracer = tracing_init_dentry();
        if (!d_tracer)
@@ -2425,11 +3063,11 @@ static __init int ftrace_init_debugfs(void)
 
        ftrace_init_dyn_debugfs(d_tracer);
 
-       entry = debugfs_create_file("set_ftrace_pid", 0644, d_tracer,
-                                   NULL, &ftrace_pid_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs "
-                          "'set_ftrace_pid' entry\n");
+       trace_create_file("set_ftrace_pid", 0644, d_tracer,
+                           NULL, &ftrace_pid_fops);
+
+       ftrace_profile_debugfs(d_tracer);
+
        return 0;
 }
 fs_initcall(ftrace_init_debugfs);
@@ -2538,7 +3176,7 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
-static atomic_t ftrace_graph_active;
+static int ftrace_graph_active;
 static struct notifier_block ftrace_suspend_notifier;
 
 int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace)
@@ -2580,12 +3218,12 @@ static int alloc_retstack_tasklist(struct ftrace_ret_stack **ret_stack_list)
                }
 
                if (t->ret_stack == NULL) {
-                       t->curr_ret_stack = -1;
-                       /* Make sure IRQs see the -1 first: */
-                       barrier();
-                       t->ret_stack = ret_stack_list[start++];
                        atomic_set(&t->tracing_graph_pause, 0);
                        atomic_set(&t->trace_overrun, 0);
+                       t->curr_ret_stack = -1;
+                       /* Make sure the tasks see the -1 first: */
+                       smp_wmb();
+                       t->ret_stack = ret_stack_list[start++];
                }
        } while_each_thread(g, t);
 
@@ -2643,8 +3281,10 @@ static int start_graph_tracing(void)
                return -ENOMEM;
 
        /* The cpu_boot init_task->ret_stack will never be freed */
-       for_each_online_cpu(cpu)
-               ftrace_graph_init_task(idle_task(cpu));
+       for_each_online_cpu(cpu) {
+               if (!idle_task(cpu)->ret_stack)
+                       ftrace_graph_init_task(idle_task(cpu));
+       }
 
        do {
                ret = alloc_retstack_tasklist(ret_stack_list);
@@ -2690,7 +3330,7 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc,
        mutex_lock(&ftrace_lock);
 
        /* we currently allow only one tracer registered at a time */
-       if (atomic_read(&ftrace_graph_active)) {
+       if (ftrace_graph_active) {
                ret = -EBUSY;
                goto out;
        }
@@ -2698,10 +3338,10 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc,
        ftrace_suspend_notifier.notifier_call = ftrace_suspend_notifier_call;
        register_pm_notifier(&ftrace_suspend_notifier);
 
-       atomic_inc(&ftrace_graph_active);
+       ftrace_graph_active++;
        ret = start_graph_tracing();
        if (ret) {
-               atomic_dec(&ftrace_graph_active);
+               ftrace_graph_active--;
                goto out;
        }
 
@@ -2719,10 +3359,10 @@ void unregister_ftrace_graph(void)
 {
        mutex_lock(&ftrace_lock);
 
-       if (!unlikely(atomic_read(&ftrace_graph_active)))
+       if (unlikely(!ftrace_graph_active))
                goto out;
 
-       atomic_dec(&ftrace_graph_active);
+       ftrace_graph_active--;
        unregister_trace_sched_switch(ftrace_graph_probe_sched_switch);
        ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub;
        ftrace_graph_entry = ftrace_graph_entry_stub;
@@ -2736,18 +3376,25 @@ void unregister_ftrace_graph(void)
 /* Allocate a return stack for newly created task */
 void ftrace_graph_init_task(struct task_struct *t)
 {
-       if (atomic_read(&ftrace_graph_active)) {
-               t->ret_stack = kmalloc(FTRACE_RETFUNC_DEPTH
+       /* Make sure we do not use the parent ret_stack */
+       t->ret_stack = NULL;
+
+       if (ftrace_graph_active) {
+               struct ftrace_ret_stack *ret_stack;
+
+               ret_stack = kmalloc(FTRACE_RETFUNC_DEPTH
                                * sizeof(struct ftrace_ret_stack),
                                GFP_KERNEL);
-               if (!t->ret_stack)
+               if (!ret_stack)
                        return;
                t->curr_ret_stack = -1;
                atomic_set(&t->tracing_graph_pause, 0);
                atomic_set(&t->trace_overrun, 0);
                t->ftrace_timestamp = 0;
-       } else
-               t->ret_stack = NULL;
+               /* make curr_ret_stack visable before we add the ret_stack */
+               smp_wmb();
+               t->ret_stack = ret_stack;
+       }
 }
 
 void ftrace_graph_exit_task(struct task_struct *t)
index 5011f4d91e375c2895cdc074299caafdf058ca38..86cdf671d7e288c0998a4b14e2b2f2f2c709fdb2 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/dcache.h>
 #include <linux/fs.h>
 
-#include <trace/kmemtrace.h>
+#include <linux/kmemtrace.h>
 
 #include "trace_output.h"
 #include "trace.h"
@@ -42,6 +42,7 @@ static inline void kmemtrace_alloc(enum kmemtrace_type_id type_id,
                                   gfp_t gfp_flags,
                                   int node)
 {
+       struct ftrace_event_call *call = &event_kmem_alloc;
        struct trace_array *tr = kmemtrace_array;
        struct kmemtrace_alloc_entry *entry;
        struct ring_buffer_event *event;
@@ -62,7 +63,8 @@ static inline void kmemtrace_alloc(enum kmemtrace_type_id type_id,
        entry->gfp_flags        = gfp_flags;
        entry->node             = node;
 
-       ring_buffer_unlock_commit(tr->buffer, event);
+       if (!filter_check_discard(call, entry, tr->buffer, event))
+               ring_buffer_unlock_commit(tr->buffer, event);
 
        trace_wake_up();
 }
@@ -71,6 +73,7 @@ static inline void kmemtrace_free(enum kmemtrace_type_id type_id,
                                  unsigned long call_site,
                                  const void *ptr)
 {
+       struct ftrace_event_call *call = &event_kmem_free;
        struct trace_array *tr = kmemtrace_array;
        struct kmemtrace_free_entry *entry;
        struct ring_buffer_event *event;
@@ -86,7 +89,8 @@ static inline void kmemtrace_free(enum kmemtrace_type_id type_id,
        entry->call_site        = call_site;
        entry->ptr              = ptr;
 
-       ring_buffer_unlock_commit(tr->buffer, event);
+       if (!filter_check_discard(call, entry, tr->buffer, event))
+               ring_buffer_unlock_commit(tr->buffer, event);
 
        trace_wake_up();
 }
index 960cbf44c844a17dd156b25927d6e98c89840600..2e642b2b7253d11ddce40c657a471f007561be65 100644 (file)
 
 #include "trace.h"
 
+/*
+ * The ring buffer header is special. We must manually up keep it.
+ */
+int ring_buffer_print_entry_header(struct trace_seq *s)
+{
+       int ret;
+
+       ret = trace_seq_printf(s, "# compressed entry header\n");
+       ret = trace_seq_printf(s, "\ttype_len    :    5 bits\n");
+       ret = trace_seq_printf(s, "\ttime_delta  :   27 bits\n");
+       ret = trace_seq_printf(s, "\tarray       :   32 bits\n");
+       ret = trace_seq_printf(s, "\n");
+       ret = trace_seq_printf(s, "\tpadding     : type == %d\n",
+                              RINGBUF_TYPE_PADDING);
+       ret = trace_seq_printf(s, "\ttime_extend : type == %d\n",
+                              RINGBUF_TYPE_TIME_EXTEND);
+       ret = trace_seq_printf(s, "\tdata max type_len  == %d\n",
+                              RINGBUF_TYPE_DATA_TYPE_LEN_MAX);
+
+       return ret;
+}
+
 /*
  * The ring buffer is made up of a list of pages. A separate list of pages is
  * allocated for each CPU. A writer may only write to a buffer that is
@@ -182,7 +204,10 @@ EXPORT_SYMBOL_GPL(tracing_is_on);
 
 #define RB_EVNT_HDR_SIZE (offsetof(struct ring_buffer_event, array))
 #define RB_ALIGNMENT           4U
-#define RB_MAX_SMALL_DATA      28
+#define RB_MAX_SMALL_DATA      (RB_ALIGNMENT * RINGBUF_TYPE_DATA_TYPE_LEN_MAX)
+
+/* define RINGBUF_TYPE_DATA for 'case RINGBUF_TYPE_DATA:' */
+#define RINGBUF_TYPE_DATA 0 ... RINGBUF_TYPE_DATA_TYPE_LEN_MAX
 
 enum {
        RB_LEN_TIME_EXTEND = 8,
@@ -191,48 +216,28 @@ enum {
 
 static inline int rb_null_event(struct ring_buffer_event *event)
 {
-       return event->type == RINGBUF_TYPE_PADDING && event->time_delta == 0;
+       return event->type_len == RINGBUF_TYPE_PADDING
+                       && event->time_delta == 0;
 }
 
 static inline int rb_discarded_event(struct ring_buffer_event *event)
 {
-       return event->type == RINGBUF_TYPE_PADDING && event->time_delta;
+       return event->type_len == RINGBUF_TYPE_PADDING && event->time_delta;
 }
 
 static void rb_event_set_padding(struct ring_buffer_event *event)
 {
-       event->type = RINGBUF_TYPE_PADDING;
+       event->type_len = RINGBUF_TYPE_PADDING;
        event->time_delta = 0;
 }
 
-/**
- * ring_buffer_event_discard - discard an event in the ring buffer
- * @buffer: the ring buffer
- * @event: the event to discard
- *
- * Sometimes a event that is in the ring buffer needs to be ignored.
- * This function lets the user discard an event in the ring buffer
- * and then that event will not be read later.
- *
- * Note, it is up to the user to be careful with this, and protect
- * against races. If the user discards an event that has been consumed
- * it is possible that it could corrupt the ring buffer.
- */
-void ring_buffer_event_discard(struct ring_buffer_event *event)
-{
-       event->type = RINGBUF_TYPE_PADDING;
-       /* time delta must be non zero */
-       if (!event->time_delta)
-               event->time_delta = 1;
-}
-
 static unsigned
 rb_event_data_length(struct ring_buffer_event *event)
 {
        unsigned length;
 
-       if (event->len)
-               length = event->len * RB_ALIGNMENT;
+       if (event->type_len)
+               length = event->type_len * RB_ALIGNMENT;
        else
                length = event->array[0];
        return length + RB_EVNT_HDR_SIZE;
@@ -242,12 +247,12 @@ rb_event_data_length(struct ring_buffer_event *event)
 static unsigned
 rb_event_length(struct ring_buffer_event *event)
 {
-       switch (event->type) {
+       switch (event->type_len) {
        case RINGBUF_TYPE_PADDING:
                if (rb_null_event(event))
                        /* undefined */
                        return -1;
-               return rb_event_data_length(event);
+               return  event->array[0] + RB_EVNT_HDR_SIZE;
 
        case RINGBUF_TYPE_TIME_EXTEND:
                return RB_LEN_TIME_EXTEND;
@@ -271,7 +276,7 @@ rb_event_length(struct ring_buffer_event *event)
 unsigned ring_buffer_event_length(struct ring_buffer_event *event)
 {
        unsigned length = rb_event_length(event);
-       if (event->type != RINGBUF_TYPE_DATA)
+       if (event->type_len > RINGBUF_TYPE_DATA_TYPE_LEN_MAX)
                return length;
        length -= RB_EVNT_HDR_SIZE;
        if (length > RB_MAX_SMALL_DATA + sizeof(event->array[0]))
@@ -284,9 +289,9 @@ EXPORT_SYMBOL_GPL(ring_buffer_event_length);
 static void *
 rb_event_data(struct ring_buffer_event *event)
 {
-       BUG_ON(event->type != RINGBUF_TYPE_DATA);
+       BUG_ON(event->type_len > RINGBUF_TYPE_DATA_TYPE_LEN_MAX);
        /* If length is in len field, then array[0] has the data */
-       if (event->len)
+       if (event->type_len)
                return (void *)&event->array[0];
        /* Otherwise length is in array[0] and array[1] has the data */
        return (void *)&event->array[1];
@@ -316,9 +321,10 @@ struct buffer_data_page {
 };
 
 struct buffer_page {
+       struct list_head list;          /* list of buffer pages */
        local_t          write;         /* index for next write */
        unsigned         read;          /* index for next read */
-       struct list_head list;          /* list of free pages */
+       local_t          entries;       /* entries on this page */
        struct buffer_data_page *page;  /* Actual data page */
 };
 
@@ -361,6 +367,34 @@ static inline int test_time_stamp(u64 delta)
 
 #define BUF_PAGE_SIZE (PAGE_SIZE - BUF_PAGE_HDR_SIZE)
 
+/* Max payload is BUF_PAGE_SIZE - header (8bytes) */
+#define BUF_MAX_DATA_SIZE (BUF_PAGE_SIZE - (sizeof(u32) * 2))
+
+/* Max number of timestamps that can fit on a page */
+#define RB_TIMESTAMPS_PER_PAGE (BUF_PAGE_SIZE / RB_LEN_TIME_STAMP)
+
+int ring_buffer_print_page_header(struct trace_seq *s)
+{
+       struct buffer_data_page field;
+       int ret;
+
+       ret = trace_seq_printf(s, "\tfield: u64 timestamp;\t"
+                              "offset:0;\tsize:%u;\n",
+                              (unsigned int)sizeof(field.time_stamp));
+
+       ret = trace_seq_printf(s, "\tfield: local_t commit;\t"
+                              "offset:%u;\tsize:%u;\n",
+                              (unsigned int)offsetof(typeof(field), commit),
+                              (unsigned int)sizeof(field.commit));
+
+       ret = trace_seq_printf(s, "\tfield: char data;\t"
+                              "offset:%u;\tsize:%u;\n",
+                              (unsigned int)offsetof(typeof(field), data),
+                              (unsigned int)BUF_PAGE_SIZE);
+
+       return ret;
+}
+
 /*
  * head_page == tail_page && head == tail then buffer is empty.
  */
@@ -375,8 +409,11 @@ struct ring_buffer_per_cpu {
        struct buffer_page              *tail_page;     /* write to tail */
        struct buffer_page              *commit_page;   /* committed pages */
        struct buffer_page              *reader_page;
+       unsigned long                   nmi_dropped;
+       unsigned long                   commit_overrun;
        unsigned long                   overrun;
-       unsigned long                   entries;
+       unsigned long                   read;
+       local_t                         entries;
        u64                             write_stamp;
        u64                             read_stamp;
        atomic_t                        record_disabled;
@@ -389,6 +426,8 @@ struct ring_buffer {
        atomic_t                        record_disabled;
        cpumask_var_t                   cpumask;
 
+       struct lock_class_key           *reader_lock_key;
+
        struct mutex                    mutex;
 
        struct ring_buffer_per_cpu      **buffers;
@@ -420,13 +459,18 @@ struct ring_buffer_iter {
 /* Up this if you want to test the TIME_EXTENTS and normalization */
 #define DEBUG_SHIFT 0
 
+static inline u64 rb_time_stamp(struct ring_buffer *buffer, int cpu)
+{
+       /* shift to debug/test normalization and TIME_EXTENTS */
+       return buffer->clock() << DEBUG_SHIFT;
+}
+
 u64 ring_buffer_time_stamp(struct ring_buffer *buffer, int cpu)
 {
        u64 time;
 
        preempt_disable_notrace();
-       /* shift to debug/test normalization and TIME_EXTENTS */
-       time = buffer->clock() << DEBUG_SHIFT;
+       time = rb_time_stamp(buffer, cpu);
        preempt_enable_no_resched_notrace();
 
        return time;
@@ -523,6 +567,7 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu)
        cpu_buffer->cpu = cpu;
        cpu_buffer->buffer = buffer;
        spin_lock_init(&cpu_buffer->reader_lock);
+       lockdep_set_class(&cpu_buffer->reader_lock, buffer->reader_lock_key);
        cpu_buffer->lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
        INIT_LIST_HEAD(&cpu_buffer->pages);
 
@@ -593,7 +638,8 @@ static int rb_cpu_notify(struct notifier_block *self,
  * when the buffer wraps. If this flag is not set, the buffer will
  * drop data when the tail hits the head.
  */
-struct ring_buffer *ring_buffer_alloc(unsigned long size, unsigned flags)
+struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags,
+                                       struct lock_class_key *key)
 {
        struct ring_buffer *buffer;
        int bsize;
@@ -616,6 +662,7 @@ struct ring_buffer *ring_buffer_alloc(unsigned long size, unsigned flags)
        buffer->pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
        buffer->flags = flags;
        buffer->clock = trace_clock_local;
+       buffer->reader_lock_key = key;
 
        /* need at least two pages */
        if (buffer->pages == 1)
@@ -673,7 +720,7 @@ struct ring_buffer *ring_buffer_alloc(unsigned long size, unsigned flags)
        kfree(buffer);
        return NULL;
 }
-EXPORT_SYMBOL_GPL(ring_buffer_alloc);
+EXPORT_SYMBOL_GPL(__ring_buffer_alloc);
 
 /**
  * ring_buffer_free - free a ring buffer.
@@ -947,31 +994,6 @@ static inline unsigned rb_head_size(struct ring_buffer_per_cpu *cpu_buffer)
        return rb_page_commit(cpu_buffer->head_page);
 }
 
-/*
- * When the tail hits the head and the buffer is in overwrite mode,
- * the head jumps to the next page and all content on the previous
- * page is discarded. But before doing so, we update the overrun
- * variable of the buffer.
- */
-static void rb_update_overflow(struct ring_buffer_per_cpu *cpu_buffer)
-{
-       struct ring_buffer_event *event;
-       unsigned long head;
-
-       for (head = 0; head < rb_head_size(cpu_buffer);
-            head += rb_event_length(event)) {
-
-               event = __rb_page_index(cpu_buffer->head_page, head);
-               if (RB_WARN_ON(cpu_buffer, rb_null_event(event)))
-                       return;
-               /* Only count data entries */
-               if (event->type != RINGBUF_TYPE_DATA)
-                       continue;
-               cpu_buffer->overrun++;
-               cpu_buffer->entries--;
-       }
-}
-
 static inline void rb_inc_page(struct ring_buffer_per_cpu *cpu_buffer,
                               struct buffer_page **bpage)
 {
@@ -991,7 +1013,7 @@ rb_event_index(struct ring_buffer_event *event)
        return (addr & ~PAGE_MASK) - (PAGE_SIZE - BUF_PAGE_SIZE);
 }
 
-static int
+static inline int
 rb_is_commit(struct ring_buffer_per_cpu *cpu_buffer,
             struct ring_buffer_event *event)
 {
@@ -1110,28 +1132,21 @@ static void
 rb_update_event(struct ring_buffer_event *event,
                         unsigned type, unsigned length)
 {
-       event->type = type;
+       event->type_len = type;
 
        switch (type) {
 
        case RINGBUF_TYPE_PADDING:
-               break;
-
        case RINGBUF_TYPE_TIME_EXTEND:
-               event->len = DIV_ROUND_UP(RB_LEN_TIME_EXTEND, RB_ALIGNMENT);
-               break;
-
        case RINGBUF_TYPE_TIME_STAMP:
-               event->len = DIV_ROUND_UP(RB_LEN_TIME_STAMP, RB_ALIGNMENT);
                break;
 
-       case RINGBUF_TYPE_DATA:
+       case 0:
                length -= RB_EVNT_HDR_SIZE;
-               if (length > RB_MAX_SMALL_DATA) {
-                       event->len = 0;
+               if (length > RB_MAX_SMALL_DATA)
                        event->array[0] = length;
-               else
-                       event->len = DIV_ROUND_UP(length, RB_ALIGNMENT);
+               else
+                       event->type_len = DIV_ROUND_UP(length, RB_ALIGNMENT);
                break;
        default:
                BUG();
@@ -1155,131 +1170,156 @@ static unsigned rb_calculate_event_length(unsigned length)
        return length;
 }
 
+
 static struct ring_buffer_event *
-__rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
-                 unsigned type, unsigned long length, u64 *ts)
+rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer,
+            unsigned long length, unsigned long tail,
+            struct buffer_page *commit_page,
+            struct buffer_page *tail_page, u64 *ts)
 {
-       struct buffer_page *tail_page, *head_page, *reader_page, *commit_page;
-       unsigned long tail, write;
+       struct buffer_page *next_page, *head_page, *reader_page;
        struct ring_buffer *buffer = cpu_buffer->buffer;
        struct ring_buffer_event *event;
-       unsigned long flags;
        bool lock_taken = false;
+       unsigned long flags;
 
-       commit_page = cpu_buffer->commit_page;
-       /* we just need to protect against interrupts */
-       barrier();
-       tail_page = cpu_buffer->tail_page;
-       write = local_add_return(length, &tail_page->write);
-       tail = write - length;
+       next_page = tail_page;
 
-       /* See if we shot pass the end of this buffer page */
-       if (write > BUF_PAGE_SIZE) {
-               struct buffer_page *next_page = tail_page;
+       local_irq_save(flags);
+       /*
+        * Since the write to the buffer is still not
+        * fully lockless, we must be careful with NMIs.
+        * The locks in the writers are taken when a write
+        * crosses to a new page. The locks protect against
+        * races with the readers (this will soon be fixed
+        * with a lockless solution).
+        *
+        * Because we can not protect against NMIs, and we
+        * want to keep traces reentrant, we need to manage
+        * what happens when we are in an NMI.
+        *
+        * NMIs can happen after we take the lock.
+        * If we are in an NMI, only take the lock
+        * if it is not already taken. Otherwise
+        * simply fail.
+        */
+       if (unlikely(in_nmi())) {
+               if (!__raw_spin_trylock(&cpu_buffer->lock)) {
+                       cpu_buffer->nmi_dropped++;
+                       goto out_reset;
+               }
+       } else
+               __raw_spin_lock(&cpu_buffer->lock);
 
-               local_irq_save(flags);
-               /*
-                * Since the write to the buffer is still not
-                * fully lockless, we must be careful with NMIs.
-                * The locks in the writers are taken when a write
-                * crosses to a new page. The locks protect against
-                * races with the readers (this will soon be fixed
-                * with a lockless solution).
-                *
-                * Because we can not protect against NMIs, and we
-                * want to keep traces reentrant, we need to manage
-                * what happens when we are in an NMI.
-                *
-                * NMIs can happen after we take the lock.
-                * If we are in an NMI, only take the lock
-                * if it is not already taken. Otherwise
-                * simply fail.
-                */
-               if (unlikely(in_nmi())) {
-                       if (!__raw_spin_trylock(&cpu_buffer->lock))
-                               goto out_reset;
-               } else
-                       __raw_spin_lock(&cpu_buffer->lock);
+       lock_taken = true;
 
-               lock_taken = true;
+       rb_inc_page(cpu_buffer, &next_page);
 
-               rb_inc_page(cpu_buffer, &next_page);
+       head_page = cpu_buffer->head_page;
+       reader_page = cpu_buffer->reader_page;
 
-               head_page = cpu_buffer->head_page;
-               reader_page = cpu_buffer->reader_page;
+       /* we grabbed the lock before incrementing */
+       if (RB_WARN_ON(cpu_buffer, next_page == reader_page))
+               goto out_reset;
 
-               /* we grabbed the lock before incrementing */
-               if (RB_WARN_ON(cpu_buffer, next_page == reader_page))
-                       goto out_reset;
+       /*
+        * If for some reason, we had an interrupt storm that made
+        * it all the way around the buffer, bail, and warn
+        * about it.
+        */
+       if (unlikely(next_page == commit_page)) {
+               cpu_buffer->commit_overrun++;
+               goto out_reset;
+       }
 
-               /*
-                * If for some reason, we had an interrupt storm that made
-                * it all the way around the buffer, bail, and warn
-                * about it.
-                */
-               if (unlikely(next_page == commit_page)) {
-                       WARN_ON_ONCE(1);
+       if (next_page == head_page) {
+               if (!(buffer->flags & RB_FL_OVERWRITE))
                        goto out_reset;
-               }
 
-               if (next_page == head_page) {
-                       if (!(buffer->flags & RB_FL_OVERWRITE))
-                               goto out_reset;
-
-                       /* tail_page has not moved yet? */
-                       if (tail_page == cpu_buffer->tail_page) {
-                               /* count overflows */
-                               rb_update_overflow(cpu_buffer);
+               /* tail_page has not moved yet? */
+               if (tail_page == cpu_buffer->tail_page) {
+                       /* count overflows */
+                       cpu_buffer->overrun +=
+                               local_read(&head_page->entries);
 
-                               rb_inc_page(cpu_buffer, &head_page);
-                               cpu_buffer->head_page = head_page;
-                               cpu_buffer->head_page->read = 0;
-                       }
+                       rb_inc_page(cpu_buffer, &head_page);
+                       cpu_buffer->head_page = head_page;
+                       cpu_buffer->head_page->read = 0;
                }
+       }
 
-               /*
-                * If the tail page is still the same as what we think
-                * it is, then it is up to us to update the tail
-                * pointer.
-                */
-               if (tail_page == cpu_buffer->tail_page) {
-                       local_set(&next_page->write, 0);
-                       local_set(&next_page->page->commit, 0);
-                       cpu_buffer->tail_page = next_page;
+       /*
+        * If the tail page is still the same as what we think
+        * it is, then it is up to us to update the tail
+        * pointer.
+        */
+       if (tail_page == cpu_buffer->tail_page) {
+               local_set(&next_page->write, 0);
+               local_set(&next_page->entries, 0);
+               local_set(&next_page->page->commit, 0);
+               cpu_buffer->tail_page = next_page;
+
+               /* reread the time stamp */
+               *ts = rb_time_stamp(buffer, cpu_buffer->cpu);
+               cpu_buffer->tail_page->page->time_stamp = *ts;
+       }
 
-                       /* reread the time stamp */
-                       *ts = ring_buffer_time_stamp(buffer, cpu_buffer->cpu);
-                       cpu_buffer->tail_page->page->time_stamp = *ts;
-               }
+       /*
+        * The actual tail page has moved forward.
+        */
+       if (tail < BUF_PAGE_SIZE) {
+               /* Mark the rest of the page with padding */
+               event = __rb_page_index(tail_page, tail);
+               rb_event_set_padding(event);
+       }
 
-               /*
-                * The actual tail page has moved forward.
-                */
-               if (tail < BUF_PAGE_SIZE) {
-                       /* Mark the rest of the page with padding */
-                       event = __rb_page_index(tail_page, tail);
-                       rb_event_set_padding(event);
-               }
+       /* Set the write back to the previous setting */
+       local_sub(length, &tail_page->write);
 
-               if (tail <= BUF_PAGE_SIZE)
-                       /* Set the write back to the previous setting */
-                       local_set(&tail_page->write, tail);
+       /*
+        * If this was a commit entry that failed,
+        * increment that too
+        */
+       if (tail_page == cpu_buffer->commit_page &&
+           tail == rb_commit_index(cpu_buffer)) {
+               rb_set_commit_to_write(cpu_buffer);
+       }
 
-               /*
-                * If this was a commit entry that failed,
-                * increment that too
-                */
-               if (tail_page == cpu_buffer->commit_page &&
-                   tail == rb_commit_index(cpu_buffer)) {
-                       rb_set_commit_to_write(cpu_buffer);
-               }
+       __raw_spin_unlock(&cpu_buffer->lock);
+       local_irq_restore(flags);
+
+       /* fail and let the caller try again */
+       return ERR_PTR(-EAGAIN);
+
+ out_reset:
+       /* reset write */
+       local_sub(length, &tail_page->write);
 
+       if (likely(lock_taken))
                __raw_spin_unlock(&cpu_buffer->lock);
-               local_irq_restore(flags);
+       local_irq_restore(flags);
+       return NULL;
+}
 
-               /* fail and let the caller try again */
-               return ERR_PTR(-EAGAIN);
-       }
+static struct ring_buffer_event *
+__rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
+                 unsigned type, unsigned long length, u64 *ts)
+{
+       struct buffer_page *tail_page, *commit_page;
+       struct ring_buffer_event *event;
+       unsigned long tail, write;
+
+       commit_page = cpu_buffer->commit_page;
+       /* we just need to protect against interrupts */
+       barrier();
+       tail_page = cpu_buffer->tail_page;
+       write = local_add_return(length, &tail_page->write);
+       tail = write - length;
+
+       /* See if we shot pass the end of this buffer page */
+       if (write > BUF_PAGE_SIZE)
+               return rb_move_tail(cpu_buffer, length, tail,
+                                   commit_page, tail_page, ts);
 
        /* We reserved something on the buffer */
 
@@ -1289,6 +1329,10 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
        event = __rb_page_index(tail_page, tail);
        rb_update_event(event, type, length);
 
+       /* The passed in type is zero for DATA */
+       if (likely(!type))
+               local_inc(&tail_page->entries);
+
        /*
         * If this is a commit and the tail is zero, then update
         * this page's time stamp.
@@ -1297,16 +1341,38 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
                cpu_buffer->commit_page->page->time_stamp = *ts;
 
        return event;
+}
 
- out_reset:
-       /* reset write */
-       if (tail <= BUF_PAGE_SIZE)
-               local_set(&tail_page->write, tail);
+static inline int
+rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer,
+                 struct ring_buffer_event *event)
+{
+       unsigned long new_index, old_index;
+       struct buffer_page *bpage;
+       unsigned long index;
+       unsigned long addr;
 
-       if (likely(lock_taken))
-               __raw_spin_unlock(&cpu_buffer->lock);
-       local_irq_restore(flags);
-       return NULL;
+       new_index = rb_event_index(event);
+       old_index = new_index + rb_event_length(event);
+       addr = (unsigned long)event;
+       addr &= PAGE_MASK;
+
+       bpage = cpu_buffer->tail_page;
+
+       if (bpage->page == (void *)addr && rb_page_write(bpage) == old_index) {
+               /*
+                * This is on the tail page. It is possible that
+                * a write could come in and move the tail page
+                * and write to the next page. That is fine
+                * because we just shorten what is on this page.
+                */
+               index = local_cmpxchg(&bpage->write, old_index, new_index);
+               if (index == old_index)
+                       return 1;
+       }
+
+       /* could not discard */
+       return 0;
 }
 
 static int
@@ -1351,16 +1417,23 @@ rb_add_time_stamp(struct ring_buffer_per_cpu *cpu_buffer,
                        event->array[0] = *delta >> TS_SHIFT;
                } else {
                        cpu_buffer->commit_page->page->time_stamp = *ts;
-                       event->time_delta = 0;
-                       event->array[0] = 0;
+                       /* try to discard, since we do not need this */
+                       if (!rb_try_to_discard(cpu_buffer, event)) {
+                               /* nope, just zero it */
+                               event->time_delta = 0;
+                               event->array[0] = 0;
+                       }
                }
                cpu_buffer->write_stamp = *ts;
                /* let the caller know this was the commit */
                ret = 1;
        } else {
-               /* Darn, this is just wasted space */
-               event->time_delta = 0;
-               event->array[0] = 0;
+               /* Try to discard the event */
+               if (!rb_try_to_discard(cpu_buffer, event)) {
+                       /* Darn, this is just wasted space */
+                       event->time_delta = 0;
+                       event->array[0] = 0;
+               }
                ret = 0;
        }
 
@@ -1371,13 +1444,14 @@ rb_add_time_stamp(struct ring_buffer_per_cpu *cpu_buffer,
 
 static struct ring_buffer_event *
 rb_reserve_next_event(struct ring_buffer_per_cpu *cpu_buffer,
-                     unsigned type, unsigned long length)
+                     unsigned long length)
 {
        struct ring_buffer_event *event;
-       u64 ts, delta;
+       u64 ts, delta = 0;
        int commit = 0;
        int nr_loops = 0;
 
+       length = rb_calculate_event_length(length);
  again:
        /*
         * We allow for interrupts to reenter here and do a trace.
@@ -1391,7 +1465,7 @@ rb_reserve_next_event(struct ring_buffer_per_cpu *cpu_buffer,
        if (RB_WARN_ON(cpu_buffer, ++nr_loops > 1000))
                return NULL;
 
-       ts = ring_buffer_time_stamp(cpu_buffer->buffer, cpu_buffer->cpu);
+       ts = rb_time_stamp(cpu_buffer->buffer, cpu_buffer->cpu);
 
        /*
         * Only the first commit can update the timestamp.
@@ -1401,23 +1475,24 @@ rb_reserve_next_event(struct ring_buffer_per_cpu *cpu_buffer,
         * also be made. But only the entry that did the actual
         * commit will be something other than zero.
         */
-       if (cpu_buffer->tail_page == cpu_buffer->commit_page &&
-           rb_page_write(cpu_buffer->tail_page) ==
-           rb_commit_index(cpu_buffer)) {
+       if (likely(cpu_buffer->tail_page == cpu_buffer->commit_page &&
+                  rb_page_write(cpu_buffer->tail_page) ==
+                  rb_commit_index(cpu_buffer))) {
+               u64 diff;
 
-               delta = ts - cpu_buffer->write_stamp;
+               diff = ts - cpu_buffer->write_stamp;
 
-               /* make sure this delta is calculated here */
+               /* make sure this diff is calculated here */
                barrier();
 
                /* Did the write stamp get updated already? */
                if (unlikely(ts < cpu_buffer->write_stamp))
-                       delta = 0;
+                       goto get_event;
 
-               if (test_time_stamp(delta)) {
+               delta = diff;
+               if (unlikely(test_time_stamp(delta))) {
 
                        commit = rb_add_time_stamp(cpu_buffer, &ts, &delta);
-
                        if (commit == -EBUSY)
                                return NULL;
 
@@ -1426,12 +1501,11 @@ rb_reserve_next_event(struct ring_buffer_per_cpu *cpu_buffer,
 
                        RB_WARN_ON(cpu_buffer, commit < 0);
                }
-       } else
-               /* Non commits have zero deltas */
-               delta = 0;
+       }
 
-       event = __rb_reserve_next(cpu_buffer, type, length, &ts);
-       if (PTR_ERR(event) == -EAGAIN)
+ get_event:
+       event = __rb_reserve_next(cpu_buffer, 0, length, &ts);
+       if (unlikely(PTR_ERR(event) == -EAGAIN))
                goto again;
 
        if (!event) {
@@ -1448,7 +1522,7 @@ rb_reserve_next_event(struct ring_buffer_per_cpu *cpu_buffer,
         * If the timestamp was commited, make the commit our entry
         * now so that we will update it when needed.
         */
-       if (commit)
+       if (unlikely(commit))
                rb_set_commit_event(cpu_buffer, event);
        else if (!rb_is_commit(cpu_buffer, event))
                delta = 0;
@@ -1458,6 +1532,36 @@ rb_reserve_next_event(struct ring_buffer_per_cpu *cpu_buffer,
        return event;
 }
 
+#define TRACE_RECURSIVE_DEPTH 16
+
+static int trace_recursive_lock(void)
+{
+       current->trace_recursion++;
+
+       if (likely(current->trace_recursion < TRACE_RECURSIVE_DEPTH))
+               return 0;
+
+       /* Disable all tracing before we do anything else */
+       tracing_off_permanent();
+
+       printk_once(KERN_WARNING "Tracing recursion: depth[%ld]:"
+                   "HC[%lu]:SC[%lu]:NMI[%lu]\n",
+                   current->trace_recursion,
+                   hardirq_count() >> HARDIRQ_SHIFT,
+                   softirq_count() >> SOFTIRQ_SHIFT,
+                   in_nmi());
+
+       WARN_ON_ONCE(1);
+       return -1;
+}
+
+static void trace_recursive_unlock(void)
+{
+       WARN_ON_ONCE(!current->trace_recursion);
+
+       current->trace_recursion--;
+}
+
 static DEFINE_PER_CPU(int, rb_need_resched);
 
 /**
@@ -1491,6 +1595,9 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, unsigned long length)
        /* If we are tracing schedule, we don't want to recurse */
        resched = ftrace_preempt_disable();
 
+       if (trace_recursive_lock())
+               goto out_nocheck;
+
        cpu = raw_smp_processor_id();
 
        if (!cpumask_test_cpu(cpu, buffer->cpumask))
@@ -1501,11 +1608,10 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, unsigned long length)
        if (atomic_read(&cpu_buffer->record_disabled))
                goto out;
 
-       length = rb_calculate_event_length(length);
-       if (length > BUF_PAGE_SIZE)
+       if (length > BUF_MAX_DATA_SIZE)
                goto out;
 
-       event = rb_reserve_next_event(cpu_buffer, RINGBUF_TYPE_DATA, length);
+       event = rb_reserve_next_event(cpu_buffer, length);
        if (!event)
                goto out;
 
@@ -1520,6 +1626,9 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, unsigned long length)
        return event;
 
  out:
+       trace_recursive_unlock();
+
+ out_nocheck:
        ftrace_preempt_enable(resched);
        return NULL;
 }
@@ -1528,7 +1637,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_lock_reserve);
 static void rb_commit(struct ring_buffer_per_cpu *cpu_buffer,
                      struct ring_buffer_event *event)
 {
-       cpu_buffer->entries++;
+       local_inc(&cpu_buffer->entries);
 
        /* Only process further if we own the commit */
        if (!rb_is_commit(cpu_buffer, event))
@@ -1558,6 +1667,8 @@ int ring_buffer_unlock_commit(struct ring_buffer *buffer,
 
        rb_commit(cpu_buffer, event);
 
+       trace_recursive_unlock();
+
        /*
         * Only the last preempt count needs to restore preemption.
         */
@@ -1570,6 +1681,99 @@ int ring_buffer_unlock_commit(struct ring_buffer *buffer,
 }
 EXPORT_SYMBOL_GPL(ring_buffer_unlock_commit);
 
+static inline void rb_event_discard(struct ring_buffer_event *event)
+{
+       /* array[0] holds the actual length for the discarded event */
+       event->array[0] = rb_event_data_length(event) - RB_EVNT_HDR_SIZE;
+       event->type_len = RINGBUF_TYPE_PADDING;
+       /* time delta must be non zero */
+       if (!event->time_delta)
+               event->time_delta = 1;
+}
+
+/**
+ * ring_buffer_event_discard - discard any event in the ring buffer
+ * @event: the event to discard
+ *
+ * Sometimes a event that is in the ring buffer needs to be ignored.
+ * This function lets the user discard an event in the ring buffer
+ * and then that event will not be read later.
+ *
+ * Note, it is up to the user to be careful with this, and protect
+ * against races. If the user discards an event that has been consumed
+ * it is possible that it could corrupt the ring buffer.
+ */
+void ring_buffer_event_discard(struct ring_buffer_event *event)
+{
+       rb_event_discard(event);
+}
+EXPORT_SYMBOL_GPL(ring_buffer_event_discard);
+
+/**
+ * ring_buffer_commit_discard - discard an event that has not been committed
+ * @buffer: the ring buffer
+ * @event: non committed event to discard
+ *
+ * This is similar to ring_buffer_event_discard but must only be
+ * performed on an event that has not been committed yet. The difference
+ * is that this will also try to free the event from the ring buffer
+ * if another event has not been added behind it.
+ *
+ * If another event has been added behind it, it will set the event
+ * up as discarded, and perform the commit.
+ *
+ * If this function is called, do not call ring_buffer_unlock_commit on
+ * the event.
+ */
+void ring_buffer_discard_commit(struct ring_buffer *buffer,
+                               struct ring_buffer_event *event)
+{
+       struct ring_buffer_per_cpu *cpu_buffer;
+       int cpu;
+
+       /* The event is discarded regardless */
+       rb_event_discard(event);
+
+       /*
+        * This must only be called if the event has not been
+        * committed yet. Thus we can assume that preemption
+        * is still disabled.
+        */
+       RB_WARN_ON(buffer, preemptible());
+
+       cpu = smp_processor_id();
+       cpu_buffer = buffer->buffers[cpu];
+
+       if (!rb_try_to_discard(cpu_buffer, event))
+               goto out;
+
+       /*
+        * The commit is still visible by the reader, so we
+        * must increment entries.
+        */
+       local_inc(&cpu_buffer->entries);
+ out:
+       /*
+        * If a write came in and pushed the tail page
+        * we still need to update the commit pointer
+        * if we were the commit.
+        */
+       if (rb_is_commit(cpu_buffer, event))
+               rb_set_commit_to_write(cpu_buffer);
+
+       trace_recursive_unlock();
+
+       /*
+        * Only the last preempt count needs to restore preemption.
+        */
+       if (preempt_count() == 1)
+               ftrace_preempt_enable(per_cpu(rb_need_resched, cpu));
+       else
+               preempt_enable_no_resched_notrace();
+
+}
+EXPORT_SYMBOL_GPL(ring_buffer_discard_commit);
+
 /**
  * ring_buffer_write - write data to the buffer without reserving
  * @buffer: The ring buffer to write to.
@@ -1589,7 +1793,6 @@ int ring_buffer_write(struct ring_buffer *buffer,
 {
        struct ring_buffer_per_cpu *cpu_buffer;
        struct ring_buffer_event *event;
-       unsigned long event_length;
        void *body;
        int ret = -EBUSY;
        int cpu, resched;
@@ -1612,9 +1815,10 @@ int ring_buffer_write(struct ring_buffer *buffer,
        if (atomic_read(&cpu_buffer->record_disabled))
                goto out;
 
-       event_length = rb_calculate_event_length(length);
-       event = rb_reserve_next_event(cpu_buffer,
-                                     RINGBUF_TYPE_DATA, event_length);
+       if (length > BUF_MAX_DATA_SIZE)
+               goto out;
+
+       event = rb_reserve_next_event(cpu_buffer, length);
        if (!event)
                goto out;
 
@@ -1728,7 +1932,8 @@ unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu)
                return 0;
 
        cpu_buffer = buffer->buffers[cpu];
-       ret = cpu_buffer->entries;
+       ret = (local_read(&cpu_buffer->entries) - cpu_buffer->overrun)
+               - cpu_buffer->read;
 
        return ret;
 }
@@ -1754,6 +1959,47 @@ unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu)
 }
 EXPORT_SYMBOL_GPL(ring_buffer_overrun_cpu);
 
+/**
+ * ring_buffer_nmi_dropped_cpu - get the number of nmis that were dropped
+ * @buffer: The ring buffer
+ * @cpu: The per CPU buffer to get the number of overruns from
+ */
+unsigned long ring_buffer_nmi_dropped_cpu(struct ring_buffer *buffer, int cpu)
+{
+       struct ring_buffer_per_cpu *cpu_buffer;
+       unsigned long ret;
+
+       if (!cpumask_test_cpu(cpu, buffer->cpumask))
+               return 0;
+
+       cpu_buffer = buffer->buffers[cpu];
+       ret = cpu_buffer->nmi_dropped;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ring_buffer_nmi_dropped_cpu);
+
+/**
+ * ring_buffer_commit_overrun_cpu - get the number of overruns caused by commits
+ * @buffer: The ring buffer
+ * @cpu: The per CPU buffer to get the number of overruns from
+ */
+unsigned long
+ring_buffer_commit_overrun_cpu(struct ring_buffer *buffer, int cpu)
+{
+       struct ring_buffer_per_cpu *cpu_buffer;
+       unsigned long ret;
+
+       if (!cpumask_test_cpu(cpu, buffer->cpumask))
+               return 0;
+
+       cpu_buffer = buffer->buffers[cpu];
+       ret = cpu_buffer->commit_overrun;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ring_buffer_commit_overrun_cpu);
+
 /**
  * ring_buffer_entries - get the number of entries in a buffer
  * @buffer: The ring buffer
@@ -1770,7 +2016,8 @@ unsigned long ring_buffer_entries(struct ring_buffer *buffer)
        /* if you care about this being correct, lock the buffer */
        for_each_buffer_cpu(buffer, cpu) {
                cpu_buffer = buffer->buffers[cpu];
-               entries += cpu_buffer->entries;
+               entries += (local_read(&cpu_buffer->entries) -
+                           cpu_buffer->overrun) - cpu_buffer->read;
        }
 
        return entries;
@@ -1862,7 +2109,7 @@ rb_update_read_stamp(struct ring_buffer_per_cpu *cpu_buffer,
 {
        u64 delta;
 
-       switch (event->type) {
+       switch (event->type_len) {
        case RINGBUF_TYPE_PADDING:
                return;
 
@@ -1893,7 +2140,7 @@ rb_update_iter_read_stamp(struct ring_buffer_iter *iter,
 {
        u64 delta;
 
-       switch (event->type) {
+       switch (event->type_len) {
        case RINGBUF_TYPE_PADDING:
                return;
 
@@ -1966,6 +2213,7 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
        cpu_buffer->reader_page->list.prev = reader->list.prev;
 
        local_set(&cpu_buffer->reader_page->write, 0);
+       local_set(&cpu_buffer->reader_page->entries, 0);
        local_set(&cpu_buffer->reader_page->page->commit, 0);
 
        /* Make the reader page now replace the head */
@@ -2008,8 +2256,9 @@ static void rb_advance_reader(struct ring_buffer_per_cpu *cpu_buffer)
 
        event = rb_reader_event(cpu_buffer);
 
-       if (event->type == RINGBUF_TYPE_DATA || rb_discarded_event(event))
-               cpu_buffer->entries--;
+       if (event->type_len <= RINGBUF_TYPE_DATA_TYPE_LEN_MAX
+                       || rb_discarded_event(event))
+               cpu_buffer->read++;
 
        rb_update_read_stamp(cpu_buffer, event);
 
@@ -2031,8 +2280,8 @@ static void rb_advance_iter(struct ring_buffer_iter *iter)
         * Check if we are at the end of the buffer.
         */
        if (iter->head >= rb_page_size(iter->head_page)) {
-               if (RB_WARN_ON(buffer,
-                              iter->head_page == cpu_buffer->commit_page))
+               /* discarded commits can make the page empty */
+               if (iter->head_page == cpu_buffer->commit_page)
                        return;
                rb_inc_iter(iter);
                return;
@@ -2075,12 +2324,10 @@ rb_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts)
        /*
         * We repeat when a timestamp is encountered. It is possible
         * to get multiple timestamps from an interrupt entering just
-        * as one timestamp is about to be written. The max times
-        * that this can happen is the number of nested interrupts we
-        * can have.  Nesting 10 deep of interrupts is clearly
-        * an anomaly.
+        * as one timestamp is about to be written, or from discarded
+        * commits. The most that we can have is the number on a single page.
         */
-       if (RB_WARN_ON(cpu_buffer, ++nr_loops > 10))
+       if (RB_WARN_ON(cpu_buffer, ++nr_loops > RB_TIMESTAMPS_PER_PAGE))
                return NULL;
 
        reader = rb_get_reader_page(cpu_buffer);
@@ -2089,7 +2336,7 @@ rb_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts)
 
        event = rb_reader_event(cpu_buffer);
 
-       switch (event->type) {
+       switch (event->type_len) {
        case RINGBUF_TYPE_PADDING:
                if (rb_null_event(event))
                        RB_WARN_ON(cpu_buffer, 1);
@@ -2146,14 +2393,14 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
 
  again:
        /*
-        * We repeat when a timestamp is encountered. It is possible
-        * to get multiple timestamps from an interrupt entering just
-        * as one timestamp is about to be written. The max times
-        * that this can happen is the number of nested interrupts we
-        * can have. Nesting 10 deep of interrupts is clearly
-        * an anomaly.
+        * We repeat when a timestamp is encountered.
+        * We can get multiple timestamps by nested interrupts or also
+        * if filtering is on (discarding commits). Since discarding
+        * commits can be frequent we can get a lot of timestamps.
+        * But we limit them by not adding timestamps if they begin
+        * at the start of a page.
         */
-       if (RB_WARN_ON(cpu_buffer, ++nr_loops > 10))
+       if (RB_WARN_ON(cpu_buffer, ++nr_loops > RB_TIMESTAMPS_PER_PAGE))
                return NULL;
 
        if (rb_per_cpu_empty(cpu_buffer))
@@ -2161,7 +2408,7 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
 
        event = rb_iter_head_event(iter);
 
-       switch (event->type) {
+       switch (event->type_len) {
        case RINGBUF_TYPE_PADDING:
                if (rb_null_event(event)) {
                        rb_inc_iter(iter);
@@ -2220,7 +2467,7 @@ ring_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts)
        event = rb_buffer_peek(buffer, cpu, ts);
        spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 
-       if (event && event->type == RINGBUF_TYPE_PADDING) {
+       if (event && event->type_len == RINGBUF_TYPE_PADDING) {
                cpu_relax();
                goto again;
        }
@@ -2248,7 +2495,7 @@ ring_buffer_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
        event = rb_iter_peek(iter, ts);
        spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 
-       if (event && event->type == RINGBUF_TYPE_PADDING) {
+       if (event && event->type_len == RINGBUF_TYPE_PADDING) {
                cpu_relax();
                goto again;
        }
@@ -2293,7 +2540,7 @@ ring_buffer_consume(struct ring_buffer *buffer, int cpu, u64 *ts)
  out:
        preempt_enable();
 
-       if (event && event->type == RINGBUF_TYPE_PADDING) {
+       if (event && event->type_len == RINGBUF_TYPE_PADDING) {
                cpu_relax();
                goto again;
        }
@@ -2386,7 +2633,7 @@ ring_buffer_read(struct ring_buffer_iter *iter, u64 *ts)
  out:
        spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 
-       if (event && event->type == RINGBUF_TYPE_PADDING) {
+       if (event && event->type_len == RINGBUF_TYPE_PADDING) {
                cpu_relax();
                goto again;
        }
@@ -2411,6 +2658,7 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer)
        cpu_buffer->head_page
                = list_entry(cpu_buffer->pages.next, struct buffer_page, list);
        local_set(&cpu_buffer->head_page->write, 0);
+       local_set(&cpu_buffer->head_page->entries, 0);
        local_set(&cpu_buffer->head_page->page->commit, 0);
 
        cpu_buffer->head_page->read = 0;
@@ -2420,11 +2668,15 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer)
 
        INIT_LIST_HEAD(&cpu_buffer->reader_page->list);
        local_set(&cpu_buffer->reader_page->write, 0);
+       local_set(&cpu_buffer->reader_page->entries, 0);
        local_set(&cpu_buffer->reader_page->page->commit, 0);
        cpu_buffer->reader_page->read = 0;
 
+       cpu_buffer->nmi_dropped = 0;
+       cpu_buffer->commit_overrun = 0;
        cpu_buffer->overrun = 0;
-       cpu_buffer->entries = 0;
+       cpu_buffer->read = 0;
+       local_set(&cpu_buffer->entries, 0);
 
        cpu_buffer->write_stamp = 0;
        cpu_buffer->read_stamp = 0;
@@ -2443,6 +2695,8 @@ void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu)
        if (!cpumask_test_cpu(cpu, buffer->cpumask))
                return;
 
+       atomic_inc(&cpu_buffer->record_disabled);
+
        spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
 
        __raw_spin_lock(&cpu_buffer->lock);
@@ -2452,6 +2706,8 @@ void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu)
        __raw_spin_unlock(&cpu_buffer->lock);
 
        spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
+
+       atomic_dec(&cpu_buffer->record_disabled);
 }
 EXPORT_SYMBOL_GPL(ring_buffer_reset_cpu);
 
@@ -2578,28 +2834,6 @@ out:
 }
 EXPORT_SYMBOL_GPL(ring_buffer_swap_cpu);
 
-static void rb_remove_entries(struct ring_buffer_per_cpu *cpu_buffer,
-                             struct buffer_data_page *bpage,
-                             unsigned int offset)
-{
-       struct ring_buffer_event *event;
-       unsigned long head;
-
-       __raw_spin_lock(&cpu_buffer->lock);
-       for (head = offset; head < local_read(&bpage->commit);
-            head += rb_event_length(event)) {
-
-               event = __rb_data_page_index(bpage, head);
-               if (RB_WARN_ON(cpu_buffer, rb_null_event(event)))
-                       return;
-               /* Only count data entries */
-               if (event->type != RINGBUF_TYPE_DATA)
-                       continue;
-               cpu_buffer->entries--;
-       }
-       __raw_spin_unlock(&cpu_buffer->lock);
-}
-
 /**
  * ring_buffer_alloc_read_page - allocate a page to read from buffer
  * @buffer: the buffer to allocate for.
@@ -2630,6 +2864,7 @@ void *ring_buffer_alloc_read_page(struct ring_buffer *buffer)
 
        return bpage;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_alloc_read_page);
 
 /**
  * ring_buffer_free_read_page - free an allocated read page
@@ -2642,6 +2877,7 @@ void ring_buffer_free_read_page(struct ring_buffer *buffer, void *data)
 {
        free_page((unsigned long)data);
 }
+EXPORT_SYMBOL_GPL(ring_buffer_free_read_page);
 
 /**
  * ring_buffer_read_page - extract a page from the ring buffer
@@ -2768,16 +3004,17 @@ int ring_buffer_read_page(struct ring_buffer *buffer,
                /* we copied everything to the beginning */
                read = 0;
        } else {
+               /* update the entry counter */
+               cpu_buffer->read += local_read(&reader->entries);
+
                /* swap the pages */
                rb_init_page(bpage);
                bpage = reader->page;
                reader->page = *data_page;
                local_set(&reader->write, 0);
+               local_set(&reader->entries, 0);
                reader->read = 0;
                *data_page = bpage;
-
-               /* update the entry counter */
-               rb_remove_entries(cpu_buffer, bpage, read);
        }
        ret = read;
 
@@ -2787,6 +3024,7 @@ int ring_buffer_read_page(struct ring_buffer *buffer,
  out:
        return ret;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_read_page);
 
 static ssize_t
 rb_simple_read(struct file *filp, char __user *ubuf,
@@ -2845,14 +3083,11 @@ static const struct file_operations rb_simple_fops = {
 static __init int rb_init_debugfs(void)
 {
        struct dentry *d_tracer;
-       struct dentry *entry;
 
        d_tracer = tracing_init_dentry();
 
-       entry = debugfs_create_file("tracing_on", 0644, d_tracer,
-                                   &ring_buffer_flags, &rb_simple_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'tracing_on' entry\n");
+       trace_create_file("tracing_on", 0644, d_tracer,
+                           &ring_buffer_flags, &rb_simple_fops);
 
        return 0;
 }
diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffer_benchmark.c
new file mode 100644 (file)
index 0000000..8d68e14
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * ring buffer tester and benchmark
+ *
+ * Copyright (C) 2009 Steven Rostedt <srostedt@redhat.com>
+ */
+#include <linux/ring_buffer.h>
+#include <linux/completion.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/time.h>
+
+struct rb_page {
+       u64             ts;
+       local_t         commit;
+       char            data[4080];
+};
+
+/* run time and sleep time in seconds */
+#define RUN_TIME       10
+#define SLEEP_TIME     10
+
+/* number of events for writer to wake up the reader */
+static int wakeup_interval = 100;
+
+static int reader_finish;
+static struct completion read_start;
+static struct completion read_done;
+
+static struct ring_buffer *buffer;
+static struct task_struct *producer;
+static struct task_struct *consumer;
+static unsigned long read;
+
+static int disable_reader;
+module_param(disable_reader, uint, 0644);
+MODULE_PARM_DESC(disable_reader, "only run producer");
+
+static int read_events;
+
+static int kill_test;
+
+#define KILL_TEST()                            \
+       do {                                    \
+               if (!kill_test) {               \
+                       kill_test = 1;          \
+                       WARN_ON(1);             \
+               }                               \
+       } while (0)
+
+enum event_status {
+       EVENT_FOUND,
+       EVENT_DROPPED,
+};
+
+static enum event_status read_event(int cpu)
+{
+       struct ring_buffer_event *event;
+       int *entry;
+       u64 ts;
+
+       event = ring_buffer_consume(buffer, cpu, &ts);
+       if (!event)
+               return EVENT_DROPPED;
+
+       entry = ring_buffer_event_data(event);
+       if (*entry != cpu) {
+               KILL_TEST();
+               return EVENT_DROPPED;
+       }
+
+       read++;
+       return EVENT_FOUND;
+}
+
+static enum event_status read_page(int cpu)
+{
+       struct ring_buffer_event *event;
+       struct rb_page *rpage;
+       unsigned long commit;
+       void *bpage;
+       int *entry;
+       int ret;
+       int inc;
+       int i;
+
+       bpage = ring_buffer_alloc_read_page(buffer);
+       if (!bpage)
+               return EVENT_DROPPED;
+
+       ret = ring_buffer_read_page(buffer, &bpage, PAGE_SIZE, cpu, 1);
+       if (ret >= 0) {
+               rpage = bpage;
+               commit = local_read(&rpage->commit);
+               for (i = 0; i < commit && !kill_test; i += inc) {
+
+                       if (i >= (PAGE_SIZE - offsetof(struct rb_page, data))) {
+                               KILL_TEST();
+                               break;
+                       }
+
+                       inc = -1;
+                       event = (void *)&rpage->data[i];
+                       switch (event->type_len) {
+                       case RINGBUF_TYPE_PADDING:
+                               /* We don't expect any padding */
+                               KILL_TEST();
+                               break;
+                       case RINGBUF_TYPE_TIME_EXTEND:
+                               inc = 8;
+                               break;
+                       case 0:
+                               entry = ring_buffer_event_data(event);
+                               if (*entry != cpu) {
+                                       KILL_TEST();
+                                       break;
+                               }
+                               read++;
+                               if (!event->array[0]) {
+                                       KILL_TEST();
+                                       break;
+                               }
+                               inc = event->array[0];
+                               break;
+                       default:
+                               entry = ring_buffer_event_data(event);
+                               if (*entry != cpu) {
+                                       KILL_TEST();
+                                       break;
+                               }
+                               read++;
+                               inc = ((event->type_len + 1) * 4);
+                       }
+                       if (kill_test)
+                               break;
+
+                       if (inc <= 0) {
+                               KILL_TEST();
+                               break;
+                       }
+               }
+       }
+       ring_buffer_free_read_page(buffer, bpage);
+
+       if (ret < 0)
+               return EVENT_DROPPED;
+       return EVENT_FOUND;
+}
+
+static void ring_buffer_consumer(void)
+{
+       /* toggle between reading pages and events */
+       read_events ^= 1;
+
+       read = 0;
+       while (!reader_finish && !kill_test) {
+               int found;
+
+               do {
+                       int cpu;
+
+                       found = 0;
+                       for_each_online_cpu(cpu) {
+                               enum event_status stat;
+
+                               if (read_events)
+                                       stat = read_event(cpu);
+                               else
+                                       stat = read_page(cpu);
+
+                               if (kill_test)
+                                       break;
+                               if (stat == EVENT_FOUND)
+                                       found = 1;
+                       }
+               } while (found && !kill_test);
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (reader_finish)
+                       break;
+
+               schedule();
+               __set_current_state(TASK_RUNNING);
+       }
+       reader_finish = 0;
+       complete(&read_done);
+}
+
+static void ring_buffer_producer(void)
+{
+       struct timeval start_tv;
+       struct timeval end_tv;
+       unsigned long long time;
+       unsigned long long entries;
+       unsigned long long overruns;
+       unsigned long missed = 0;
+       unsigned long hit = 0;
+       unsigned long avg;
+       int cnt = 0;
+
+       /*
+        * Hammer the buffer for 10 secs (this may
+        * make the system stall)
+        */
+       pr_info("Starting ring buffer hammer\n");
+       do_gettimeofday(&start_tv);
+       do {
+               struct ring_buffer_event *event;
+               int *entry;
+
+               event = ring_buffer_lock_reserve(buffer, 10);
+               if (!event) {
+                       missed++;
+               } else {
+                       hit++;
+                       entry = ring_buffer_event_data(event);
+                       *entry = smp_processor_id();
+                       ring_buffer_unlock_commit(buffer, event);
+               }
+               do_gettimeofday(&end_tv);
+
+               cnt++;
+               if (consumer && !(cnt % wakeup_interval))
+                       wake_up_process(consumer);
+
+#ifndef CONFIG_PREEMPT
+               /*
+                * If we are a non preempt kernel, the 10 second run will
+                * stop everything while it runs. Instead, we will call
+                * cond_resched and also add any time that was lost by a
+                * rescedule.
+                *
+                * Do a cond resched at the same frequency we would wake up
+                * the reader.
+                */
+               if (cnt % wakeup_interval)
+                       cond_resched();
+#endif
+
+       } while (end_tv.tv_sec < (start_tv.tv_sec + RUN_TIME) && !kill_test);
+       pr_info("End ring buffer hammer\n");
+
+       if (consumer) {
+               /* Init both completions here to avoid races */
+               init_completion(&read_start);
+               init_completion(&read_done);
+               /* the completions must be visible before the finish var */
+               smp_wmb();
+               reader_finish = 1;
+               /* finish var visible before waking up the consumer */
+               smp_wmb();
+               wake_up_process(consumer);
+               wait_for_completion(&read_done);
+       }
+
+       time = end_tv.tv_sec - start_tv.tv_sec;
+       time *= USEC_PER_SEC;
+       time += (long long)((long)end_tv.tv_usec - (long)start_tv.tv_usec);
+
+       entries = ring_buffer_entries(buffer);
+       overruns = ring_buffer_overruns(buffer);
+
+       if (kill_test)
+               pr_info("ERROR!\n");
+       pr_info("Time:     %lld (usecs)\n", time);
+       pr_info("Overruns: %lld\n", overruns);
+       if (disable_reader)
+               pr_info("Read:     (reader disabled)\n");
+       else
+               pr_info("Read:     %ld  (by %s)\n", read,
+                       read_events ? "events" : "pages");
+       pr_info("Entries:  %lld\n", entries);
+       pr_info("Total:    %lld\n", entries + overruns + read);
+       pr_info("Missed:   %ld\n", missed);
+       pr_info("Hit:      %ld\n", hit);
+
+       /* Convert time from usecs to millisecs */
+       do_div(time, USEC_PER_MSEC);
+       if (time)
+               hit /= (long)time;
+       else
+               pr_info("TIME IS ZERO??\n");
+
+       pr_info("Entries per millisec: %ld\n", hit);
+
+       if (hit) {
+               /* Calculate the average time in nanosecs */
+               avg = NSEC_PER_MSEC / hit;
+               pr_info("%ld ns per entry\n", avg);
+       }
+
+       if (missed) {
+               if (time)
+                       missed /= (long)time;
+
+               pr_info("Total iterations per millisec: %ld\n", hit + missed);
+
+               /* it is possible that hit + missed will overflow and be zero */
+               if (!(hit + missed)) {
+                       pr_info("hit + missed overflowed and totalled zero!\n");
+                       hit--; /* make it non zero */
+               }
+
+               /* Caculate the average time in nanosecs */
+               avg = NSEC_PER_MSEC / (hit + missed);
+               pr_info("%ld ns per entry\n", avg);
+       }
+}
+
+static void wait_to_die(void)
+{
+       set_current_state(TASK_INTERRUPTIBLE);
+       while (!kthread_should_stop()) {
+               schedule();
+               set_current_state(TASK_INTERRUPTIBLE);
+       }
+       __set_current_state(TASK_RUNNING);
+}
+
+static int ring_buffer_consumer_thread(void *arg)
+{
+       while (!kthread_should_stop() && !kill_test) {
+               complete(&read_start);
+
+               ring_buffer_consumer();
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (kthread_should_stop() || kill_test)
+                       break;
+
+               schedule();
+               __set_current_state(TASK_RUNNING);
+       }
+       __set_current_state(TASK_RUNNING);
+
+       if (kill_test)
+               wait_to_die();
+
+       return 0;
+}
+
+static int ring_buffer_producer_thread(void *arg)
+{
+       init_completion(&read_start);
+
+       while (!kthread_should_stop() && !kill_test) {
+               ring_buffer_reset(buffer);
+
+               if (consumer) {
+                       smp_wmb();
+                       wake_up_process(consumer);
+                       wait_for_completion(&read_start);
+               }
+
+               ring_buffer_producer();
+
+               pr_info("Sleeping for 10 secs\n");
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ * SLEEP_TIME);
+               __set_current_state(TASK_RUNNING);
+       }
+
+       if (kill_test)
+               wait_to_die();
+
+       return 0;
+}
+
+static int __init ring_buffer_benchmark_init(void)
+{
+       int ret;
+
+       /* make a one meg buffer in overwite mode */
+       buffer = ring_buffer_alloc(1000000, RB_FL_OVERWRITE);
+       if (!buffer)
+               return -ENOMEM;
+
+       if (!disable_reader) {
+               consumer = kthread_create(ring_buffer_consumer_thread,
+                                         NULL, "rb_consumer");
+               ret = PTR_ERR(consumer);
+               if (IS_ERR(consumer))
+                       goto out_fail;
+       }
+
+       producer = kthread_run(ring_buffer_producer_thread,
+                              NULL, "rb_producer");
+       ret = PTR_ERR(producer);
+
+       if (IS_ERR(producer))
+               goto out_kill;
+
+       return 0;
+
+ out_kill:
+       if (consumer)
+               kthread_stop(consumer);
+
+ out_fail:
+       ring_buffer_free(buffer);
+       return ret;
+}
+
+static void __exit ring_buffer_benchmark_exit(void)
+{
+       kthread_stop(producer);
+       if (consumer)
+               kthread_stop(consumer);
+       ring_buffer_free(buffer);
+}
+
+module_init(ring_buffer_benchmark_init);
+module_exit(ring_buffer_benchmark_exit);
+
+MODULE_AUTHOR("Steven Rostedt");
+MODULE_DESCRIPTION("ring_buffer_benchmark");
+MODULE_LICENSE("GPL");
index cda81ec58d9fe1e723388826de8966b274b71d0a..8acd9b81a5d76046ee52c9d1dc9224cc43edb1c2 100644 (file)
@@ -171,6 +171,13 @@ static struct trace_array  global_trace;
 
 static DEFINE_PER_CPU(struct trace_array_cpu, global_trace_cpu);
 
+int filter_current_check_discard(struct ftrace_event_call *call, void *rec,
+                                struct ring_buffer_event *event)
+{
+       return filter_check_discard(call, rec, global_trace.buffer, event);
+}
+EXPORT_SYMBOL_GPL(filter_current_check_discard);
+
 cycle_t ftrace_now(int cpu)
 {
        u64 ts;
@@ -255,7 +262,8 @@ static DECLARE_WAIT_QUEUE_HEAD(trace_wait);
 
 /* trace_flags holds trace_options default values */
 unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
-       TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME;
+       TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME |
+       TRACE_ITER_GRAPH_TIME;
 
 /**
  * trace_wake_up - wake up tasks waiting for trace input
@@ -317,6 +325,7 @@ static const char *trace_options[] = {
        "latency-format",
        "global-clock",
        "sleep-time",
+       "graph-time",
        NULL
 };
 
@@ -402,17 +411,6 @@ static ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt)
        return cnt;
 }
 
-static void
-trace_print_seq(struct seq_file *m, struct trace_seq *s)
-{
-       int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len;
-
-       s->buffer[len] = 0;
-       seq_puts(m, s->buffer);
-
-       trace_seq_init(s);
-}
-
 /**
  * update_max_tr - snapshot all trace buffers from global_trace to max_tr
  * @tr: tracer
@@ -641,6 +639,16 @@ void tracing_reset_online_cpus(struct trace_array *tr)
                tracing_reset(tr, cpu);
 }
 
+void tracing_reset_current(int cpu)
+{
+       tracing_reset(&global_trace, cpu);
+}
+
+void tracing_reset_current_online_cpus(void)
+{
+       tracing_reset_online_cpus(&global_trace);
+}
+
 #define SAVED_CMDLINES 128
 #define NO_CMDLINE_MAP UINT_MAX
 static unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1];
@@ -800,6 +808,7 @@ void trace_find_cmdline(int pid, char comm[])
                return;
        }
 
+       preempt_disable();
        __raw_spin_lock(&trace_cmdline_lock);
        map = map_pid_to_cmdline[pid];
        if (map != NO_CMDLINE_MAP)
@@ -808,6 +817,7 @@ void trace_find_cmdline(int pid, char comm[])
                strcpy(comm, "<...>");
 
        __raw_spin_unlock(&trace_cmdline_lock);
+       preempt_enable();
 }
 
 void tracing_record_cmdline(struct task_struct *tsk)
@@ -840,7 +850,7 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags,
 }
 
 struct ring_buffer_event *trace_buffer_lock_reserve(struct trace_array *tr,
-                                                   unsigned char type,
+                                                   int type,
                                                    unsigned long len,
                                                    unsigned long flags, int pc)
 {
@@ -883,30 +893,40 @@ void trace_buffer_unlock_commit(struct trace_array *tr,
 }
 
 struct ring_buffer_event *
-trace_current_buffer_lock_reserve(unsigned char type, unsigned long len,
+trace_current_buffer_lock_reserve(int type, unsigned long len,
                                  unsigned long flags, int pc)
 {
        return trace_buffer_lock_reserve(&global_trace,
                                         type, len, flags, pc);
 }
+EXPORT_SYMBOL_GPL(trace_current_buffer_lock_reserve);
 
 void trace_current_buffer_unlock_commit(struct ring_buffer_event *event,
                                        unsigned long flags, int pc)
 {
-       return __trace_buffer_unlock_commit(&global_trace, event, flags, pc, 1);
+       __trace_buffer_unlock_commit(&global_trace, event, flags, pc, 1);
 }
+EXPORT_SYMBOL_GPL(trace_current_buffer_unlock_commit);
 
 void trace_nowake_buffer_unlock_commit(struct ring_buffer_event *event,
                                        unsigned long flags, int pc)
 {
-       return __trace_buffer_unlock_commit(&global_trace, event, flags, pc, 0);
+       __trace_buffer_unlock_commit(&global_trace, event, flags, pc, 0);
+}
+EXPORT_SYMBOL_GPL(trace_nowake_buffer_unlock_commit);
+
+void trace_current_buffer_discard_commit(struct ring_buffer_event *event)
+{
+       ring_buffer_discard_commit(global_trace.buffer, event);
 }
+EXPORT_SYMBOL_GPL(trace_current_buffer_discard_commit);
 
 void
 trace_function(struct trace_array *tr,
               unsigned long ip, unsigned long parent_ip, unsigned long flags,
               int pc)
 {
+       struct ftrace_event_call *call = &event_function;
        struct ring_buffer_event *event;
        struct ftrace_entry *entry;
 
@@ -921,7 +941,9 @@ trace_function(struct trace_array *tr,
        entry   = ring_buffer_event_data(event);
        entry->ip                       = ip;
        entry->parent_ip                = parent_ip;
-       ring_buffer_unlock_commit(tr->buffer, event);
+
+       if (!filter_check_discard(call, entry, tr->buffer, event))
+               ring_buffer_unlock_commit(tr->buffer, event);
 }
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
@@ -930,6 +952,7 @@ static int __trace_graph_entry(struct trace_array *tr,
                                unsigned long flags,
                                int pc)
 {
+       struct ftrace_event_call *call = &event_funcgraph_entry;
        struct ring_buffer_event *event;
        struct ftrace_graph_ent_entry *entry;
 
@@ -942,7 +965,8 @@ static int __trace_graph_entry(struct trace_array *tr,
                return 0;
        entry   = ring_buffer_event_data(event);
        entry->graph_ent                        = *trace;
-       ring_buffer_unlock_commit(global_trace.buffer, event);
+       if (!filter_current_check_discard(call, entry, event))
+               ring_buffer_unlock_commit(global_trace.buffer, event);
 
        return 1;
 }
@@ -952,6 +976,7 @@ static void __trace_graph_return(struct trace_array *tr,
                                unsigned long flags,
                                int pc)
 {
+       struct ftrace_event_call *call = &event_funcgraph_exit;
        struct ring_buffer_event *event;
        struct ftrace_graph_ret_entry *entry;
 
@@ -964,7 +989,8 @@ static void __trace_graph_return(struct trace_array *tr,
                return;
        entry   = ring_buffer_event_data(event);
        entry->ret                              = *trace;
-       ring_buffer_unlock_commit(global_trace.buffer, event);
+       if (!filter_current_check_discard(call, entry, event))
+               ring_buffer_unlock_commit(global_trace.buffer, event);
 }
 #endif
 
@@ -982,6 +1008,7 @@ static void __ftrace_trace_stack(struct trace_array *tr,
                                 int skip, int pc)
 {
 #ifdef CONFIG_STACKTRACE
+       struct ftrace_event_call *call = &event_kernel_stack;
        struct ring_buffer_event *event;
        struct stack_entry *entry;
        struct stack_trace trace;
@@ -999,7 +1026,8 @@ static void __ftrace_trace_stack(struct trace_array *tr,
        trace.entries           = entry->caller;
 
        save_stack_trace(&trace);
-       ring_buffer_unlock_commit(tr->buffer, event);
+       if (!filter_check_discard(call, entry, tr->buffer, event))
+               ring_buffer_unlock_commit(tr->buffer, event);
 #endif
 }
 
@@ -1024,6 +1052,7 @@ static void ftrace_trace_userstack(struct trace_array *tr,
                                   unsigned long flags, int pc)
 {
 #ifdef CONFIG_STACKTRACE
+       struct ftrace_event_call *call = &event_user_stack;
        struct ring_buffer_event *event;
        struct userstack_entry *entry;
        struct stack_trace trace;
@@ -1045,7 +1074,8 @@ static void ftrace_trace_userstack(struct trace_array *tr,
        trace.entries           = entry->caller;
 
        save_stack_trace_user(&trace);
-       ring_buffer_unlock_commit(tr->buffer, event);
+       if (!filter_check_discard(call, entry, tr->buffer, event))
+               ring_buffer_unlock_commit(tr->buffer, event);
 #endif
 }
 
@@ -1089,6 +1119,7 @@ tracing_sched_switch_trace(struct trace_array *tr,
                           struct task_struct *next,
                           unsigned long flags, int pc)
 {
+       struct ftrace_event_call *call = &event_context_switch;
        struct ring_buffer_event *event;
        struct ctx_switch_entry *entry;
 
@@ -1104,7 +1135,9 @@ tracing_sched_switch_trace(struct trace_array *tr,
        entry->next_prio                = next->prio;
        entry->next_state               = next->state;
        entry->next_cpu = task_cpu(next);
-       trace_buffer_unlock_commit(tr, event, flags, pc);
+
+       if (!filter_check_discard(call, entry, tr->buffer, event))
+               trace_buffer_unlock_commit(tr, event, flags, pc);
 }
 
 void
@@ -1113,6 +1146,7 @@ tracing_sched_wakeup_trace(struct trace_array *tr,
                           struct task_struct *curr,
                           unsigned long flags, int pc)
 {
+       struct ftrace_event_call *call = &event_wakeup;
        struct ring_buffer_event *event;
        struct ctx_switch_entry *entry;
 
@@ -1129,7 +1163,8 @@ tracing_sched_wakeup_trace(struct trace_array *tr,
        entry->next_state               = wakee->state;
        entry->next_cpu                 = task_cpu(wakee);
 
-       ring_buffer_unlock_commit(tr->buffer, event);
+       if (!filter_check_discard(call, entry, tr->buffer, event))
+               ring_buffer_unlock_commit(tr->buffer, event);
        ftrace_trace_stack(tr, flags, 6, pc);
        ftrace_trace_userstack(tr, flags, pc);
 }
@@ -1230,11 +1265,13 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
                (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
        static u32 trace_buf[TRACE_BUF_SIZE];
 
+       struct ftrace_event_call *call = &event_bprint;
        struct ring_buffer_event *event;
        struct trace_array *tr = &global_trace;
        struct trace_array_cpu *data;
        struct bprint_entry *entry;
        unsigned long flags;
+       int disable;
        int resched;
        int cpu, len = 0, size, pc;
 
@@ -1249,7 +1286,8 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
        cpu = raw_smp_processor_id();
        data = tr->data[cpu];
 
-       if (unlikely(atomic_read(&data->disabled)))
+       disable = atomic_inc_return(&data->disabled);
+       if (unlikely(disable != 1))
                goto out;
 
        /* Lockdep uses trace_printk for lock tracing */
@@ -1269,13 +1307,15 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
        entry->fmt                      = fmt;
 
        memcpy(entry->buf, trace_buf, sizeof(u32) * len);
-       ring_buffer_unlock_commit(tr->buffer, event);
+       if (!filter_check_discard(call, entry, tr->buffer, event))
+               ring_buffer_unlock_commit(tr->buffer, event);
 
 out_unlock:
        __raw_spin_unlock(&trace_buf_lock);
        local_irq_restore(flags);
 
 out:
+       atomic_dec_return(&data->disabled);
        ftrace_preempt_enable(resched);
        unpause_graph_tracing();
 
@@ -1288,12 +1328,14 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
        static raw_spinlock_t trace_buf_lock = __RAW_SPIN_LOCK_UNLOCKED;
        static char trace_buf[TRACE_BUF_SIZE];
 
+       struct ftrace_event_call *call = &event_print;
        struct ring_buffer_event *event;
        struct trace_array *tr = &global_trace;
        struct trace_array_cpu *data;
        int cpu, len = 0, size, pc;
        struct print_entry *entry;
        unsigned long irq_flags;
+       int disable;
 
        if (tracing_disabled || tracing_selftest_running)
                return 0;
@@ -1303,7 +1345,8 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
        cpu = raw_smp_processor_id();
        data = tr->data[cpu];
 
-       if (unlikely(atomic_read(&data->disabled)))
+       disable = atomic_inc_return(&data->disabled);
+       if (unlikely(disable != 1))
                goto out;
 
        pause_graph_tracing();
@@ -1323,13 +1366,15 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
 
        memcpy(&entry->buf, trace_buf, len);
        entry->buf[len] = 0;
-       ring_buffer_unlock_commit(tr->buffer, event);
+       if (!filter_check_discard(call, entry, tr->buffer, event))
+               ring_buffer_unlock_commit(tr->buffer, event);
 
  out_unlock:
        __raw_spin_unlock(&trace_buf_lock);
        raw_local_irq_restore(irq_flags);
        unpause_graph_tracing();
  out:
+       atomic_dec_return(&data->disabled);
        preempt_enable_notrace();
 
        return len;
@@ -1526,12 +1571,14 @@ static void *s_start(struct seq_file *m, loff_t *pos)
                p = s_next(m, p, &l);
        }
 
+       trace_event_read_lock();
        return p;
 }
 
 static void s_stop(struct seq_file *m, void *p)
 {
        atomic_dec(&trace_record_cmdline_disabled);
+       trace_event_read_unlock();
 }
 
 static void print_lat_help_header(struct seq_file *m)
@@ -1774,6 +1821,7 @@ static int trace_empty(struct trace_iterator *iter)
        return 1;
 }
 
+/*  Called with trace_event_read_lock() held. */
 static enum print_line_t print_trace_line(struct trace_iterator *iter)
 {
        enum print_line_t ret;
@@ -2396,6 +2444,56 @@ static const struct file_operations tracing_readme_fops = {
        .read           = tracing_readme_read,
 };
 
+static ssize_t
+tracing_saved_cmdlines_read(struct file *file, char __user *ubuf,
+                               size_t cnt, loff_t *ppos)
+{
+       char *buf_comm;
+       char *file_buf;
+       char *buf;
+       int len = 0;
+       int pid;
+       int i;
+
+       file_buf = kmalloc(SAVED_CMDLINES*(16+TASK_COMM_LEN), GFP_KERNEL);
+       if (!file_buf)
+               return -ENOMEM;
+
+       buf_comm = kmalloc(TASK_COMM_LEN, GFP_KERNEL);
+       if (!buf_comm) {
+               kfree(file_buf);
+               return -ENOMEM;
+       }
+
+       buf = file_buf;
+
+       for (i = 0; i < SAVED_CMDLINES; i++) {
+               int r;
+
+               pid = map_cmdline_to_pid[i];
+               if (pid == -1 || pid == NO_CMDLINE_MAP)
+                       continue;
+
+               trace_find_cmdline(pid, buf_comm);
+               r = sprintf(buf, "%d %s\n", pid, buf_comm);
+               buf += r;
+               len += r;
+       }
+
+       len = simple_read_from_buffer(ubuf, cnt, ppos,
+                                     file_buf, len);
+
+       kfree(file_buf);
+       kfree(buf_comm);
+
+       return len;
+}
+
+static const struct file_operations tracing_saved_cmdlines_fops = {
+    .open       = tracing_open_generic,
+    .read       = tracing_saved_cmdlines_read,
+};
+
 static ssize_t
 tracing_ctrl_read(struct file *filp, char __user *ubuf,
                  size_t cnt, loff_t *ppos)
@@ -2728,6 +2826,9 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
        /* trace pipe does not show start of buffer */
        cpumask_setall(iter->started);
 
+       if (trace_flags & TRACE_ITER_LATENCY_FMT)
+               iter->iter_flags |= TRACE_FILE_LAT_FMT;
+
        iter->cpu_file = cpu_file;
        iter->tr = &global_trace;
        mutex_init(&iter->mutex);
@@ -2915,6 +3016,7 @@ waitagain:
               offsetof(struct trace_iterator, seq));
        iter->pos = -1;
 
+       trace_event_read_lock();
        while (find_next_entry_inc(iter) != NULL) {
                enum print_line_t ret;
                int len = iter->seq.len;
@@ -2931,6 +3033,7 @@ waitagain:
                if (iter->seq.len >= cnt)
                        break;
        }
+       trace_event_read_unlock();
 
        /* Now copy what we have to the user */
        sret = trace_seq_to_user(&iter->seq, ubuf, cnt);
@@ -3053,6 +3156,8 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
                goto out_err;
        }
 
+       trace_event_read_lock();
+
        /* Fill as many pages as possible. */
        for (i = 0, rem = len; i < PIPE_BUFFERS && rem; i++) {
                pages[i] = alloc_page(GFP_KERNEL);
@@ -3075,6 +3180,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
                trace_seq_init(&iter->seq);
        }
 
+       trace_event_read_unlock();
        mutex_unlock(&iter->mutex);
 
        spd.nr_pages = i;
@@ -3425,7 +3531,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
                .spd_release    = buffer_spd_release,
        };
        struct buffer_ref *ref;
-       int size, i;
+       int entries, size, i;
        size_t ret;
 
        if (*ppos & (PAGE_SIZE - 1)) {
@@ -3440,7 +3546,9 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
                len &= PAGE_MASK;
        }
 
-       for (i = 0; i < PIPE_BUFFERS && len; i++, len -= PAGE_SIZE) {
+       entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu);
+
+       for (i = 0; i < PIPE_BUFFERS && len && entries; i++, len -= PAGE_SIZE) {
                struct page *page;
                int r;
 
@@ -3457,7 +3565,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
                }
 
                r = ring_buffer_read_page(ref->buffer, &ref->page,
-                                         len, info->cpu, 0);
+                                         len, info->cpu, 1);
                if (r < 0) {
                        ring_buffer_free_read_page(ref->buffer,
                                                   ref->page);
@@ -3481,6 +3589,8 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
                spd.partial[i].private = (unsigned long)ref;
                spd.nr_pages++;
                *ppos += PAGE_SIZE;
+
+               entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu);
        }
 
        spd.nr_pages = i;
@@ -3508,6 +3618,45 @@ static const struct file_operations tracing_buffers_fops = {
        .llseek         = no_llseek,
 };
 
+static ssize_t
+tracing_stats_read(struct file *filp, char __user *ubuf,
+                  size_t count, loff_t *ppos)
+{
+       unsigned long cpu = (unsigned long)filp->private_data;
+       struct trace_array *tr = &global_trace;
+       struct trace_seq *s;
+       unsigned long cnt;
+
+       s = kmalloc(sizeof(*s), GFP_ATOMIC);
+       if (!s)
+               return ENOMEM;
+
+       trace_seq_init(s);
+
+       cnt = ring_buffer_entries_cpu(tr->buffer, cpu);
+       trace_seq_printf(s, "entries: %ld\n", cnt);
+
+       cnt = ring_buffer_overrun_cpu(tr->buffer, cpu);
+       trace_seq_printf(s, "overrun: %ld\n", cnt);
+
+       cnt = ring_buffer_commit_overrun_cpu(tr->buffer, cpu);
+       trace_seq_printf(s, "commit overrun: %ld\n", cnt);
+
+       cnt = ring_buffer_nmi_dropped_cpu(tr->buffer, cpu);
+       trace_seq_printf(s, "nmi dropped: %ld\n", cnt);
+
+       count = simple_read_from_buffer(ubuf, count, ppos, s->buffer, s->len);
+
+       kfree(s);
+
+       return count;
+}
+
+static const struct file_operations tracing_stats_fops = {
+       .open           = tracing_open_generic,
+       .read           = tracing_stats_read,
+};
+
 #ifdef CONFIG_DYNAMIC_FTRACE
 
 int __weak ftrace_arch_read_dyn_info(char *buf, int size)
@@ -3597,7 +3746,7 @@ struct dentry *tracing_dentry_percpu(void)
 static void tracing_init_debugfs_percpu(long cpu)
 {
        struct dentry *d_percpu = tracing_dentry_percpu();
-       struct dentry *entry, *d_cpu;
+       struct dentry *d_cpu;
        /* strlen(cpu) + MAX(log10(cpu)) + '\0' */
        char cpu_dir[7];
 
@@ -3612,21 +3761,18 @@ static void tracing_init_debugfs_percpu(long cpu)
        }
 
        /* per cpu trace_pipe */
-       entry = debugfs_create_file("trace_pipe", 0444, d_cpu,
-                               (void *) cpu, &tracing_pipe_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'trace_pipe' entry\n");
+       trace_create_file("trace_pipe", 0444, d_cpu,
+                       (void *) cpu, &tracing_pipe_fops);
 
        /* per cpu trace */
-       entry = debugfs_create_file("trace", 0644, d_cpu,
-                               (void *) cpu, &tracing_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'trace' entry\n");
+       trace_create_file("trace", 0644, d_cpu,
+                       (void *) cpu, &tracing_fops);
+
+       trace_create_file("trace_pipe_raw", 0444, d_cpu,
+                       (void *) cpu, &tracing_buffers_fops);
 
-       entry = debugfs_create_file("trace_pipe_raw", 0444, d_cpu,
-                                   (void *) cpu, &tracing_buffers_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'trace_pipe_raw' entry\n");
+       trace_create_file("stats", 0444, d_cpu,
+                       (void *) cpu, &tracing_stats_fops);
 }
 
 #ifdef CONFIG_FTRACE_SELFTEST
@@ -3782,6 +3928,22 @@ static const struct file_operations trace_options_core_fops = {
        .write = trace_options_core_write,
 };
 
+struct dentry *trace_create_file(const char *name,
+                                mode_t mode,
+                                struct dentry *parent,
+                                void *data,
+                                const struct file_operations *fops)
+{
+       struct dentry *ret;
+
+       ret = debugfs_create_file(name, mode, parent, data, fops);
+       if (!ret)
+               pr_warning("Could not create debugfs '%s' entry\n", name);
+
+       return ret;
+}
+
+
 static struct dentry *trace_options_init_dentry(void)
 {
        struct dentry *d_tracer;
@@ -3809,7 +3971,6 @@ create_trace_option_file(struct trace_option_dentry *topt,
                         struct tracer_opt *opt)
 {
        struct dentry *t_options;
-       struct dentry *entry;
 
        t_options = trace_options_init_dentry();
        if (!t_options)
@@ -3818,11 +3979,9 @@ create_trace_option_file(struct trace_option_dentry *topt,
        topt->flags = flags;
        topt->opt = opt;
 
-       entry = debugfs_create_file(opt->name, 0644, t_options, topt,
+       topt->entry = trace_create_file(opt->name, 0644, t_options, topt,
                                    &trace_options_fops);
 
-       topt->entry = entry;
-
 }
 
 static struct trace_option_dentry *
@@ -3877,123 +4036,84 @@ static struct dentry *
 create_trace_option_core_file(const char *option, long index)
 {
        struct dentry *t_options;
-       struct dentry *entry;
 
        t_options = trace_options_init_dentry();
        if (!t_options)
                return NULL;
 
-       entry = debugfs_create_file(option, 0644, t_options, (void *)index,
+       return trace_create_file(option, 0644, t_options, (void *)index,
                                    &trace_options_core_fops);
-
-       return entry;
 }
 
 static __init void create_trace_options_dir(void)
 {
        struct dentry *t_options;
-       struct dentry *entry;
        int i;
 
        t_options = trace_options_init_dentry();
        if (!t_options)
                return;
 
-       for (i = 0; trace_options[i]; i++) {
-               entry = create_trace_option_core_file(trace_options[i], i);
-               if (!entry)
-                       pr_warning("Could not create debugfs %s entry\n",
-                                  trace_options[i]);
-       }
+       for (i = 0; trace_options[i]; i++)
+               create_trace_option_core_file(trace_options[i], i);
 }
 
 static __init int tracer_init_debugfs(void)
 {
        struct dentry *d_tracer;
-       struct dentry *entry;
        int cpu;
 
        d_tracer = tracing_init_dentry();
 
-       entry = debugfs_create_file("tracing_enabled", 0644, d_tracer,
-                                   &global_trace, &tracing_ctrl_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'tracing_enabled' entry\n");
+       trace_create_file("tracing_enabled", 0644, d_tracer,
+                       &global_trace, &tracing_ctrl_fops);
 
-       entry = debugfs_create_file("trace_options", 0644, d_tracer,
-                                   NULL, &tracing_iter_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'trace_options' entry\n");
+       trace_create_file("trace_options", 0644, d_tracer,
+                       NULL, &tracing_iter_fops);
 
-       create_trace_options_dir();
+       trace_create_file("tracing_cpumask", 0644, d_tracer,
+                       NULL, &tracing_cpumask_fops);
+
+       trace_create_file("trace", 0644, d_tracer,
+                       (void *) TRACE_PIPE_ALL_CPU, &tracing_fops);
 
-       entry = debugfs_create_file("tracing_cpumask", 0644, d_tracer,
-                                   NULL, &tracing_cpumask_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'tracing_cpumask' entry\n");
-
-       entry = debugfs_create_file("trace", 0644, d_tracer,
-                                (void *) TRACE_PIPE_ALL_CPU, &tracing_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'trace' entry\n");
-
-       entry = debugfs_create_file("available_tracers", 0444, d_tracer,
-                                   &global_trace, &show_traces_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'available_tracers' entry\n");
-
-       entry = debugfs_create_file("current_tracer", 0444, d_tracer,
-                                   &global_trace, &set_tracer_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'current_tracer' entry\n");
-
-       entry = debugfs_create_file("tracing_max_latency", 0644, d_tracer,
-                                   &tracing_max_latency,
-                                   &tracing_max_lat_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs "
-                          "'tracing_max_latency' entry\n");
-
-       entry = debugfs_create_file("tracing_thresh", 0644, d_tracer,
-                                   &tracing_thresh, &tracing_max_lat_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs "
-                          "'tracing_thresh' entry\n");
-       entry = debugfs_create_file("README", 0644, d_tracer,
-                                   NULL, &tracing_readme_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'README' entry\n");
-
-       entry = debugfs_create_file("trace_pipe", 0444, d_tracer,
+       trace_create_file("available_tracers", 0444, d_tracer,
+                       &global_trace, &show_traces_fops);
+
+       trace_create_file("current_tracer", 0644, d_tracer,
+                       &global_trace, &set_tracer_fops);
+
+       trace_create_file("tracing_max_latency", 0644, d_tracer,
+                       &tracing_max_latency, &tracing_max_lat_fops);
+
+       trace_create_file("tracing_thresh", 0644, d_tracer,
+                       &tracing_thresh, &tracing_max_lat_fops);
+
+       trace_create_file("README", 0444, d_tracer,
+                       NULL, &tracing_readme_fops);
+
+       trace_create_file("trace_pipe", 0444, d_tracer,
                        (void *) TRACE_PIPE_ALL_CPU, &tracing_pipe_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs "
-                          "'trace_pipe' entry\n");
-
-       entry = debugfs_create_file("buffer_size_kb", 0644, d_tracer,
-                                   &global_trace, &tracing_entries_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs "
-                          "'buffer_size_kb' entry\n");
-
-       entry = debugfs_create_file("trace_marker", 0220, d_tracer,
-                                   NULL, &tracing_mark_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs "
-                          "'trace_marker' entry\n");
+
+       trace_create_file("buffer_size_kb", 0644, d_tracer,
+                       &global_trace, &tracing_entries_fops);
+
+       trace_create_file("trace_marker", 0220, d_tracer,
+                       NULL, &tracing_mark_fops);
+
+       trace_create_file("saved_cmdlines", 0444, d_tracer,
+                       NULL, &tracing_saved_cmdlines_fops);
 
 #ifdef CONFIG_DYNAMIC_FTRACE
-       entry = debugfs_create_file("dyn_ftrace_total_info", 0444, d_tracer,
-                                   &ftrace_update_tot_cnt,
-                                   &tracing_dyn_info_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs "
-                          "'dyn_ftrace_total_info' entry\n");
+       trace_create_file("dyn_ftrace_total_info", 0444, d_tracer,
+                       &ftrace_update_tot_cnt, &tracing_dyn_info_fops);
 #endif
 #ifdef CONFIG_SYSPROF_TRACER
        init_tracer_sysprof_debugfs(d_tracer);
 #endif
 
+       create_trace_options_dir();
+
        for_each_tracing_cpu(cpu)
                tracing_init_debugfs_percpu(cpu);
 
@@ -4064,7 +4184,8 @@ trace_printk_seq(struct trace_seq *s)
 
 static void __ftrace_dump(bool disable_tracing)
 {
-       static DEFINE_SPINLOCK(ftrace_dump_lock);
+       static raw_spinlock_t ftrace_dump_lock =
+               (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
        /* use static because iter can be a bit big for the stack */
        static struct trace_iterator iter;
        unsigned int old_userobj;
@@ -4073,7 +4194,8 @@ static void __ftrace_dump(bool disable_tracing)
        int cnt = 0, cpu;
 
        /* only one dump */
-       spin_lock_irqsave(&ftrace_dump_lock, flags);
+       local_irq_save(flags);
+       __raw_spin_lock(&ftrace_dump_lock);
        if (dump_ran)
                goto out;
 
@@ -4145,7 +4267,8 @@ static void __ftrace_dump(bool disable_tracing)
        }
 
  out:
-       spin_unlock_irqrestore(&ftrace_dump_lock, flags);
+       __raw_spin_unlock(&ftrace_dump_lock);
+       local_irq_restore(flags);
 }
 
 /* By default: disable tracing after the dump */
index e685ac2b2ba10f1dcf24fef92180d94b75f76367..6e735d4771f8ad9ddd971ee1806f904d7e44e176 100644 (file)
@@ -9,9 +9,12 @@
 #include <linux/mmiotrace.h>
 #include <linux/ftrace.h>
 #include <trace/boot.h>
-#include <trace/kmemtrace.h>
+#include <linux/kmemtrace.h>
 #include <trace/power.h>
 
+#include <linux/trace_seq.h>
+#include <linux/ftrace_event.h>
+
 enum trace_type {
        __TRACE_FIRST_TYPE = 0,
 
@@ -41,20 +44,6 @@ enum trace_type {
        __TRACE_LAST_TYPE,
 };
 
-/*
- * The trace entry - the most basic unit of tracing. This is what
- * is printed in the end as a single line in the trace output, such as:
- *
- *     bash-15816 [01]   235.197585: idle_cpu <- irq_enter
- */
-struct trace_entry {
-       unsigned char           type;
-       unsigned char           flags;
-       unsigned char           preempt_count;
-       int                     pid;
-       int                     tgid;
-};
-
 /*
  * Function trace entry - function address and parent function addres:
  */
@@ -263,8 +252,6 @@ struct trace_array_cpu {
        char                    comm[TASK_COMM_LEN];
 };
 
-struct trace_iterator;
-
 /*
  * The trace array - an array of per-CPU trace arrays. This is the
  * highest level data structure that individual tracers deal with.
@@ -339,15 +326,6 @@ extern void __ftrace_bad_type(void);
                __ftrace_bad_type();                                    \
        } while (0)
 
-/* Return values for print_line callback */
-enum print_line_t {
-       TRACE_TYPE_PARTIAL_LINE = 0,    /* Retry after flushing the seq */
-       TRACE_TYPE_HANDLED      = 1,
-       TRACE_TYPE_UNHANDLED    = 2,    /* Relay to other output functions */
-       TRACE_TYPE_NO_CONSUME   = 3     /* Handled but ask to not consume */
-};
-
-
 /*
  * An option specific to a tracer. This is a boolean value.
  * The bit is the bit index that sets its value on the
@@ -423,60 +401,30 @@ struct tracer {
        struct tracer_stat      *stats;
 };
 
-struct trace_seq {
-       unsigned char           buffer[PAGE_SIZE];
-       unsigned int            len;
-       unsigned int            readpos;
-};
-
-static inline void
-trace_seq_init(struct trace_seq *s)
-{
-       s->len = 0;
-       s->readpos = 0;
-}
-
 
 #define TRACE_PIPE_ALL_CPU     -1
 
-/*
- * Trace iterator - used by printout routines who present trace
- * results to users and which routines might sleep, etc:
- */
-struct trace_iterator {
-       struct trace_array      *tr;
-       struct tracer           *trace;
-       void                    *private;
-       int                     cpu_file;
-       struct mutex            mutex;
-       struct ring_buffer_iter *buffer_iter[NR_CPUS];
-
-       /* The below is zeroed out in pipe_read */
-       struct trace_seq        seq;
-       struct trace_entry      *ent;
-       int                     cpu;
-       u64                     ts;
-
-       unsigned long           iter_flags;
-       loff_t                  pos;
-       long                    idx;
-
-       cpumask_var_t           started;
-};
-
 int tracer_init(struct tracer *t, struct trace_array *tr);
 int tracing_is_enabled(void);
 void trace_wake_up(void);
 void tracing_reset(struct trace_array *tr, int cpu);
 void tracing_reset_online_cpus(struct trace_array *tr);
+void tracing_reset_current(int cpu);
+void tracing_reset_current_online_cpus(void);
 int tracing_open_generic(struct inode *inode, struct file *filp);
+struct dentry *trace_create_file(const char *name,
+                                mode_t mode,
+                                struct dentry *parent,
+                                void *data,
+                                const struct file_operations *fops);
+
 struct dentry *tracing_init_dentry(void);
 void init_tracer_sysprof_debugfs(struct dentry *d_tracer);
 
 struct ring_buffer_event;
 
 struct ring_buffer_event *trace_buffer_lock_reserve(struct trace_array *tr,
-                                                   unsigned char type,
+                                                   int type,
                                                    unsigned long len,
                                                    unsigned long flags,
                                                    int pc);
@@ -484,14 +432,6 @@ void trace_buffer_unlock_commit(struct trace_array *tr,
                                struct ring_buffer_event *event,
                                unsigned long flags, int pc);
 
-struct ring_buffer_event *
-trace_current_buffer_lock_reserve(unsigned char type, unsigned long len,
-                                 unsigned long flags, int pc);
-void trace_current_buffer_unlock_commit(struct ring_buffer_event *event,
-                                       unsigned long flags, int pc);
-void trace_nowake_buffer_unlock_commit(struct ring_buffer_event *event,
-                                       unsigned long flags, int pc);
-
 struct trace_entry *tracing_get_trace_entry(struct trace_array *tr,
                                                struct trace_array_cpu *data);
 
@@ -514,7 +454,6 @@ void tracing_sched_switch_trace(struct trace_array *tr,
                                struct task_struct *prev,
                                struct task_struct *next,
                                unsigned long flags, int pc);
-void tracing_record_cmdline(struct task_struct *tsk);
 
 void tracing_sched_wakeup_trace(struct trace_array *tr,
                                struct task_struct *wakee,
@@ -599,6 +538,8 @@ extern int trace_selftest_startup_sysprof(struct tracer *trace,
                                               struct trace_array *tr);
 extern int trace_selftest_startup_branch(struct tracer *trace,
                                         struct trace_array *tr);
+extern int trace_selftest_startup_hw_branches(struct tracer *trace,
+                                             struct trace_array *tr);
 #endif /* CONFIG_FTRACE_STARTUP_TEST */
 
 extern void *head_page(struct trace_array_cpu *data);
@@ -613,6 +554,8 @@ extern unsigned long trace_flags;
 /* Standard output formatting function used for function return traces */
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 extern enum print_line_t print_graph_function(struct trace_iterator *iter);
+extern enum print_line_t
+trace_print_graph_duration(unsigned long long duration, struct trace_seq *s);
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 /* TODO: make this variable */
@@ -644,7 +587,6 @@ static inline int ftrace_graph_addr(unsigned long addr)
        return 1;
 }
 #endif /* CONFIG_DYNAMIC_FTRACE */
-
 #else /* CONFIG_FUNCTION_GRAPH_TRACER */
 static inline enum print_line_t
 print_graph_function(struct trace_iterator *iter)
@@ -692,6 +634,7 @@ enum trace_iterator_flags {
        TRACE_ITER_LATENCY_FMT          = 0x40000,
        TRACE_ITER_GLOBAL_CLK           = 0x80000,
        TRACE_ITER_SLEEP_TIME           = 0x100000,
+       TRACE_ITER_GRAPH_TIME           = 0x200000,
 };
 
 /*
@@ -790,103 +733,113 @@ struct ftrace_event_field {
        char                    *type;
        int                     offset;
        int                     size;
+       int                     is_signed;
 };
 
-struct ftrace_event_call {
-       char                    *name;
-       char                    *system;
-       struct dentry           *dir;
-       int                     enabled;
-       int                     (*regfunc)(void);
-       void                    (*unregfunc)(void);
-       int                     id;
-       int                     (*raw_init)(void);
-       int                     (*show_format)(struct trace_seq *s);
-       int                     (*define_fields)(void);
-       struct list_head        fields;
+struct event_filter {
+       int                     n_preds;
        struct filter_pred      **preds;
-
-#ifdef CONFIG_EVENT_PROFILE
-       atomic_t        profile_count;
-       int             (*profile_enable)(struct ftrace_event_call *);
-       void            (*profile_disable)(struct ftrace_event_call *);
-#endif
+       char                    *filter_string;
 };
 
 struct event_subsystem {
        struct list_head        list;
        const char              *name;
        struct dentry           *entry;
-       struct filter_pred      **preds;
+       void                    *filter;
 };
 
-#define events_for_each(event)                                         \
-       for (event = __start_ftrace_events;                             \
-            (unsigned long)event < (unsigned long)__stop_ftrace_events; \
-            event++)
-
-#define MAX_FILTER_PRED 8
-
 struct filter_pred;
 
-typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event);
+typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event,
+                                int val1, int val2);
 
 struct filter_pred {
        filter_pred_fn_t fn;
        u64 val;
-       char *str_val;
+       char str_val[MAX_FILTER_STR_VAL];
        int str_len;
        char *field_name;
        int offset;
        int not;
-       int or;
-       int compound;
-       int clear;
+       int op;
+       int pop_n;
 };
 
-int trace_define_field(struct ftrace_event_call *call, char *type,
-                      char *name, int offset, int size);
-extern void filter_free_pred(struct filter_pred *pred);
-extern void filter_print_preds(struct filter_pred **preds,
+extern void print_event_filter(struct ftrace_event_call *call,
                               struct trace_seq *s);
-extern int filter_parse(char **pbuf, struct filter_pred *pred);
-extern int filter_add_pred(struct ftrace_event_call *call,
-                          struct filter_pred *pred);
-extern void filter_free_preds(struct ftrace_event_call *call);
-extern int filter_match_preds(struct ftrace_event_call *call, void *rec);
-extern void filter_free_subsystem_preds(struct event_subsystem *system);
-extern int filter_add_subsystem_pred(struct event_subsystem *system,
-                                    struct filter_pred *pred);
-
-void event_trace_printk(unsigned long ip, const char *fmt, ...);
-extern struct ftrace_event_call __start_ftrace_events[];
-extern struct ftrace_event_call __stop_ftrace_events[];
-
-#define for_each_event(event)                                          \
-       for (event = __start_ftrace_events;                             \
-            (unsigned long)event < (unsigned long)__stop_ftrace_events; \
-            event++)
+extern int apply_event_filter(struct ftrace_event_call *call,
+                             char *filter_string);
+extern int apply_subsystem_event_filter(struct event_subsystem *system,
+                                       char *filter_string);
+extern void print_subsystem_event_filter(struct event_subsystem *system,
+                                        struct trace_seq *s);
+
+static inline int
+filter_check_discard(struct ftrace_event_call *call, void *rec,
+                    struct ring_buffer *buffer,
+                    struct ring_buffer_event *event)
+{
+       if (unlikely(call->filter_active) && !filter_match_preds(call, rec)) {
+               ring_buffer_discard_commit(buffer, event);
+               return 1;
+       }
+
+       return 0;
+}
+
+#define DEFINE_COMPARISON_PRED(type)                                   \
+static int filter_pred_##type(struct filter_pred *pred, void *event,   \
+                             int val1, int val2)                       \
+{                                                                      \
+       type *addr = (type *)(event + pred->offset);                    \
+       type val = (type)pred->val;                                     \
+       int match = 0;                                                  \
+                                                                       \
+       switch (pred->op) {                                             \
+       case OP_LT:                                                     \
+               match = (*addr < val);                                  \
+               break;                                                  \
+       case OP_LE:                                                     \
+               match = (*addr <= val);                                 \
+               break;                                                  \
+       case OP_GT:                                                     \
+               match = (*addr > val);                                  \
+               break;                                                  \
+       case OP_GE:                                                     \
+               match = (*addr >= val);                                 \
+               break;                                                  \
+       default:                                                        \
+               break;                                                  \
+       }                                                               \
+                                                                       \
+       return match;                                                   \
+}
+
+#define DEFINE_EQUALITY_PRED(size)                                     \
+static int filter_pred_##size(struct filter_pred *pred, void *event,   \
+                             int val1, int val2)                       \
+{                                                                      \
+       u##size *addr = (u##size *)(event + pred->offset);              \
+       u##size val = (u##size)pred->val;                               \
+       int match;                                                      \
+                                                                       \
+       match = (val == *addr) ^ pred->not;                             \
+                                                                       \
+       return match;                                                   \
+}
+
+extern struct mutex event_mutex;
+extern struct list_head ftrace_events;
 
 extern const char *__start___trace_bprintk_fmt[];
 extern const char *__stop___trace_bprintk_fmt[];
 
-/*
- * The double __builtin_constant_p is because gcc will give us an error
- * if we try to allocate the static variable to fmt if it is not a
- * constant. Even with the outer if statement optimizing out.
- */
-#define event_trace_printk(ip, fmt, args...)                           \
-do {                                                                   \
-       __trace_printk_check_format(fmt, ##args);                       \
-       tracing_record_cmdline(current);                                \
-       if (__builtin_constant_p(fmt)) {                                \
-               static const char *trace_printk_fmt                     \
-                 __attribute__((section("__trace_printk_fmt"))) =      \
-                       __builtin_constant_p(fmt) ? fmt : NULL;         \
-                                                                       \
-               __trace_bprintk(ip, trace_printk_fmt, ##args);          \
-       } else                                                          \
-               __trace_printk(ip, fmt, ##args);                        \
-} while (0)
+#undef TRACE_EVENT_FORMAT
+#define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt)     \
+       extern struct ftrace_event_call event_##call;
+#undef TRACE_EVENT_FORMAT_NOFILTER
+#define TRACE_EVENT_FORMAT_NOFILTER(call, proto, args, fmt, tstruct, tpfmt)
+#include "trace_event_types.h"
 
 #endif /* _LINUX_KERNEL_TRACE_H */
index 7a30fc4c36423fc29f7e4bb97985ccd9e5ca9540..a29ef23ffb47080d81c41950ac4385566b193058 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/debugfs.h>
 #include <linux/ftrace.h>
 #include <linux/kallsyms.h>
+#include <linux/time.h>
 
 #include "trace.h"
 #include "trace_output.h"
@@ -67,7 +68,7 @@ initcall_call_print_line(struct trace_iterator *iter)
        trace_assign_type(field, entry);
        call = &field->boot_call;
        ts = iter->ts;
-       nsec_rem = do_div(ts, 1000000000);
+       nsec_rem = do_div(ts, NSEC_PER_SEC);
 
        ret = trace_seq_printf(s, "[%5ld.%09ld] calling  %s @ %i\n",
                        (unsigned long)ts, nsec_rem, call->func, call->caller);
@@ -92,7 +93,7 @@ initcall_ret_print_line(struct trace_iterator *iter)
        trace_assign_type(field, entry);
        init_ret = &field->boot_ret;
        ts = iter->ts;
-       nsec_rem = do_div(ts, 1000000000);
+       nsec_rem = do_div(ts, NSEC_PER_SEC);
 
        ret = trace_seq_printf(s, "[%5ld.%09ld] initcall %s "
                        "returned %d after %llu msecs\n",
index 8333715e4066eed26e53ecda1077d69c317679d3..7a7a9fd249a9c7c158d136dfc998efc9e908f35c 100644 (file)
@@ -30,6 +30,7 @@ static struct trace_array *branch_tracer;
 static void
 probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
 {
+       struct ftrace_event_call *call = &event_branch;
        struct trace_array *tr = branch_tracer;
        struct ring_buffer_event *event;
        struct trace_branch *entry;
@@ -73,7 +74,8 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
        entry->line = f->line;
        entry->correct = val == expect;
 
-       ring_buffer_unlock_commit(tr->buffer, event);
+       if (!filter_check_discard(call, entry, tr->buffer, event))
+               ring_buffer_unlock_commit(tr->buffer, event);
 
  out:
        atomic_dec(&tr->data[cpu]->disabled);
@@ -271,7 +273,7 @@ static int branch_stat_show(struct seq_file *m, void *v)
        return 0;
 }
 
-static void *annotated_branch_stat_start(void)
+static void *annotated_branch_stat_start(struct tracer_stat *trace)
 {
        return __start_annotated_branch_profile;
 }
@@ -346,7 +348,7 @@ static int all_branch_stat_headers(struct seq_file *m)
        return 0;
 }
 
-static void *all_branch_stat_start(void)
+static void *all_branch_stat_start(struct tracer_stat *trace)
 {
        return __start_branch_profile;
 }
index 22cba9970776cf4984cb93b3e3a7fc0c5687f912..5b5895afecfe425f5c917af29b13d29ff4acf918 100644 (file)
 int ftrace_profile_enable(int event_id)
 {
        struct ftrace_event_call *event;
+       int ret = -EINVAL;
 
-       for_each_event(event) {
-               if (event->id == event_id)
-                       return event->profile_enable(event);
+       mutex_lock(&event_mutex);
+       list_for_each_entry(event, &ftrace_events, list) {
+               if (event->id == event_id) {
+                       ret = event->profile_enable(event);
+                       break;
+               }
        }
+       mutex_unlock(&event_mutex);
 
-       return -EINVAL;
+       return ret;
 }
 
 void ftrace_profile_disable(int event_id)
 {
        struct ftrace_event_call *event;
 
-       for_each_event(event) {
-               if (event->id == event_id)
-                       return event->profile_disable(event);
+       mutex_lock(&event_mutex);
+       list_for_each_entry(event, &ftrace_events, list) {
+               if (event->id == event_id) {
+                       event->profile_disable(event);
+                       break;
+               }
        }
+       mutex_unlock(&event_mutex);
 }
-
index fd78bee71dd7519e03d45d38e3de9e58579af234..5e32e375134d976183bb0ae5df79abda3f029a54 100644 (file)
@@ -57,7 +57,7 @@ TRACE_EVENT_FORMAT(context_switch, TRACE_CTX, ctx_switch_entry, ignore,
        TP_RAW_FMT("%u:%u:%u  ==+ %u:%u:%u [%03u]")
 );
 
-TRACE_EVENT_FORMAT(special, TRACE_SPECIAL, special_entry, ignore,
+TRACE_EVENT_FORMAT_NOFILTER(special, TRACE_SPECIAL, special_entry, ignore,
        TRACE_STRUCT(
                TRACE_FIELD(unsigned long, arg1, arg1)
                TRACE_FIELD(unsigned long, arg2, arg2)
@@ -122,8 +122,10 @@ TRACE_EVENT_FORMAT(print, TRACE_PRINT, print_entry, ignore,
 TRACE_EVENT_FORMAT(branch, TRACE_BRANCH, trace_branch, ignore,
        TRACE_STRUCT(
                TRACE_FIELD(unsigned int, line, line)
-               TRACE_FIELD_SPECIAL(char func[TRACE_FUNC_SIZE+1], func, func)
-               TRACE_FIELD_SPECIAL(char file[TRACE_FUNC_SIZE+1], file, file)
+               TRACE_FIELD_SPECIAL(char func[TRACE_FUNC_SIZE+1], func,
+                                   TRACE_FUNC_SIZE+1, func)
+               TRACE_FIELD_SPECIAL(char file[TRACE_FUNC_SIZE+1], file,
+                                   TRACE_FUNC_SIZE+1, file)
                TRACE_FIELD(char, correct, correct)
        ),
        TP_RAW_FMT("%u:%s:%s (%u)")
@@ -139,8 +141,8 @@ TRACE_EVENT_FORMAT(hw_branch, TRACE_HW_BRANCHES, hw_branch_entry, ignore,
 
 TRACE_EVENT_FORMAT(power, TRACE_POWER, trace_power, ignore,
        TRACE_STRUCT(
-               TRACE_FIELD(ktime_t, state_data.stamp, stamp)
-               TRACE_FIELD(ktime_t, state_data.end, end)
+               TRACE_FIELD_SIGN(ktime_t, state_data.stamp, stamp, 1)
+               TRACE_FIELD_SIGN(ktime_t, state_data.end, end, 1)
                TRACE_FIELD(int, state_data.type, type)
                TRACE_FIELD(int, state_data.state, state)
        ),
index 576f4fa2af0da22cad87d1c20fb044d89c16a066..aa08be69a1b6c1fcc026359ece8613812ad1a492 100644 (file)
@@ -8,19 +8,25 @@
  *
  */
 
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/module.h>
 #include <linux/ctype.h>
+#include <linux/delay.h>
 
 #include "trace_output.h"
 
 #define TRACE_SYSTEM "TRACE_SYSTEM"
 
-static DEFINE_MUTEX(event_mutex);
+DEFINE_MUTEX(event_mutex);
+
+LIST_HEAD(ftrace_events);
 
 int trace_define_field(struct ftrace_event_call *call, char *type,
-                      char *name, int offset, int size)
+                      char *name, int offset, int size, int is_signed)
 {
        struct ftrace_event_field *field;
 
@@ -38,6 +44,7 @@ int trace_define_field(struct ftrace_event_call *call, char *type,
 
        field->offset = offset;
        field->size = size;
+       field->is_signed = is_signed;
        list_add(&field->link, &call->fields);
 
        return 0;
@@ -51,47 +58,94 @@ err:
 
        return -ENOMEM;
 }
+EXPORT_SYMBOL_GPL(trace_define_field);
 
-static void ftrace_clear_events(void)
-{
-       struct ftrace_event_call *call = (void *)__start_ftrace_events;
-
+#ifdef CONFIG_MODULES
 
-       while ((unsigned long)call < (unsigned long)__stop_ftrace_events) {
+static void trace_destroy_fields(struct ftrace_event_call *call)
+{
+       struct ftrace_event_field *field, *next;
 
-               if (call->enabled) {
-                       call->enabled = 0;
-                       call->unregfunc();
-               }
-               call++;
+       list_for_each_entry_safe(field, next, &call->fields, link) {
+               list_del(&field->link);
+               kfree(field->type);
+               kfree(field->name);
+               kfree(field);
        }
 }
 
+#endif /* CONFIG_MODULES */
+
 static void ftrace_event_enable_disable(struct ftrace_event_call *call,
                                        int enable)
 {
-
        switch (enable) {
        case 0:
                if (call->enabled) {
                        call->enabled = 0;
+                       tracing_stop_cmdline_record();
                        call->unregfunc();
                }
                break;
        case 1:
                if (!call->enabled) {
                        call->enabled = 1;
+                       tracing_start_cmdline_record();
                        call->regfunc();
                }
                break;
        }
 }
 
+static void ftrace_clear_events(void)
+{
+       struct ftrace_event_call *call;
+
+       mutex_lock(&event_mutex);
+       list_for_each_entry(call, &ftrace_events, list) {
+               ftrace_event_enable_disable(call, 0);
+       }
+       mutex_unlock(&event_mutex);
+}
+
+/*
+ * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events.
+ */
+static int __ftrace_set_clr_event(const char *match, const char *sub,
+                                 const char *event, int set)
+{
+       struct ftrace_event_call *call;
+       int ret = -EINVAL;
+
+       mutex_lock(&event_mutex);
+       list_for_each_entry(call, &ftrace_events, list) {
+
+               if (!call->name || !call->regfunc)
+                       continue;
+
+               if (match &&
+                   strcmp(match, call->name) != 0 &&
+                   strcmp(match, call->system) != 0)
+                       continue;
+
+               if (sub && strcmp(sub, call->system) != 0)
+                       continue;
+
+               if (event && strcmp(event, call->name) != 0)
+                       continue;
+
+               ftrace_event_enable_disable(call, set);
+
+               ret = 0;
+       }
+       mutex_unlock(&event_mutex);
+
+       return ret;
+}
+
 static int ftrace_set_clr_event(char *buf, int set)
 {
-       struct ftrace_event_call *call = __start_ftrace_events;
        char *event = NULL, *sub = NULL, *match;
-       int ret = -EINVAL;
 
        /*
         * The buf format can be <subsystem>:<event-name>
@@ -117,30 +171,24 @@ static int ftrace_set_clr_event(char *buf, int set)
                        event = NULL;
        }
 
-       mutex_lock(&event_mutex);
-       for_each_event(call) {
-
-               if (!call->name || !call->regfunc)
-                       continue;
-
-               if (match &&
-                   strcmp(match, call->name) != 0 &&
-                   strcmp(match, call->system) != 0)
-                       continue;
-
-               if (sub && strcmp(sub, call->system) != 0)
-                       continue;
-
-               if (event && strcmp(event, call->name) != 0)
-                       continue;
-
-               ftrace_event_enable_disable(call, set);
-
-               ret = 0;
-       }
-       mutex_unlock(&event_mutex);
+       return __ftrace_set_clr_event(match, sub, event, set);
+}
 
-       return ret;
+/**
+ * trace_set_clr_event - enable or disable an event
+ * @system: system name to match (NULL for any system)
+ * @event: event name to match (NULL for all events, within system)
+ * @set: 1 to enable, 0 to disable
+ *
+ * This is a way for other parts of the kernel to enable or disable
+ * event recording.
+ *
+ * Returns 0 on success, -EINVAL if the parameters do not match any
+ * registered events.
+ */
+int trace_set_clr_event(const char *system, const char *event, int set)
+{
+       return __ftrace_set_clr_event(NULL, system, event, set);
 }
 
 /* 128 should be much more than enough */
@@ -224,15 +272,17 @@ ftrace_event_write(struct file *file, const char __user *ubuf,
 static void *
 t_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       struct ftrace_event_call *call = m->private;
-       struct ftrace_event_call *next = call;
+       struct list_head *list = m->private;
+       struct ftrace_event_call *call;
 
        (*pos)++;
 
        for (;;) {
-               if ((unsigned long)call >= (unsigned long)__stop_ftrace_events)
+               if (list == &ftrace_events)
                        return NULL;
 
+               call = list_entry(list, struct ftrace_event_call, list);
+
                /*
                 * The ftrace subsystem is for showing formats only.
                 * They can not be enabled or disabled via the event files.
@@ -240,45 +290,51 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
                if (call->regfunc)
                        break;
 
-               call++;
-               next = call;
+               list = list->next;
        }
 
-       m->private = ++next;
+       m->private = list->next;
 
        return call;
 }
 
 static void *t_start(struct seq_file *m, loff_t *pos)
 {
+       mutex_lock(&event_mutex);
+       if (*pos == 0)
+               m->private = ftrace_events.next;
        return t_next(m, NULL, pos);
 }
 
 static void *
 s_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       struct ftrace_event_call *call = m->private;
-       struct ftrace_event_call *next;
+       struct list_head *list = m->private;
+       struct ftrace_event_call *call;
 
        (*pos)++;
 
  retry:
-       if ((unsigned long)call >= (unsigned long)__stop_ftrace_events)
+       if (list == &ftrace_events)
                return NULL;
 
+       call = list_entry(list, struct ftrace_event_call, list);
+
        if (!call->enabled) {
-               call++;
+               list = list->next;
                goto retry;
        }
 
-       next = call;
-       m->private = ++next;
+       m->private = list->next;
 
        return call;
 }
 
 static void *s_start(struct seq_file *m, loff_t *pos)
 {
+       mutex_lock(&event_mutex);
+       if (*pos == 0)
+               m->private = ftrace_events.next;
        return s_next(m, NULL, pos);
 }
 
@@ -295,12 +351,12 @@ static int t_show(struct seq_file *m, void *v)
 
 static void t_stop(struct seq_file *m, void *p)
 {
+       mutex_unlock(&event_mutex);
 }
 
 static int
 ftrace_event_seq_open(struct inode *inode, struct file *file)
 {
-       int ret;
        const struct seq_operations *seq_ops;
 
        if ((file->f_mode & FMODE_WRITE) &&
@@ -308,13 +364,7 @@ ftrace_event_seq_open(struct inode *inode, struct file *file)
                ftrace_clear_events();
 
        seq_ops = inode->i_private;
-       ret = seq_open(file, seq_ops);
-       if (!ret) {
-               struct seq_file *m = file->private_data;
-
-               m->private = __start_ftrace_events;
-       }
-       return ret;
+       return seq_open(file, seq_ops);
 }
 
 static ssize_t
@@ -374,8 +424,93 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
        return cnt;
 }
 
+static ssize_t
+system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
+                  loff_t *ppos)
+{
+       const char set_to_char[4] = { '?', '0', '1', 'X' };
+       const char *system = filp->private_data;
+       struct ftrace_event_call *call;
+       char buf[2];
+       int set = 0;
+       int ret;
+
+       mutex_lock(&event_mutex);
+       list_for_each_entry(call, &ftrace_events, list) {
+               if (!call->name || !call->regfunc)
+                       continue;
+
+               if (system && strcmp(call->system, system) != 0)
+                       continue;
+
+               /*
+                * We need to find out if all the events are set
+                * or if all events or cleared, or if we have
+                * a mixture.
+                */
+               set |= (1 << !!call->enabled);
+
+               /*
+                * If we have a mixture, no need to look further.
+                */
+               if (set == 3)
+                       break;
+       }
+       mutex_unlock(&event_mutex);
+
+       buf[0] = set_to_char[set];
+       buf[1] = '\n';
+
+       ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, 2);
+
+       return ret;
+}
+
+static ssize_t
+system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
+                   loff_t *ppos)
+{
+       const char *system = filp->private_data;
+       unsigned long val;
+       char buf[64];
+       ssize_t ret;
+
+       if (cnt >= sizeof(buf))
+               return -EINVAL;
+
+       if (copy_from_user(&buf, ubuf, cnt))
+               return -EFAULT;
+
+       buf[cnt] = 0;
+
+       ret = strict_strtoul(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       ret = tracing_update_buffers();
+       if (ret < 0)
+               return ret;
+
+       if (val != 0 && val != 1)
+               return -EINVAL;
+
+       ret = __ftrace_set_clr_event(NULL, system, NULL, val);
+       if (ret)
+               goto out;
+
+       ret = cnt;
+
+out:
+       *ppos += cnt;
+
+       return ret;
+}
+
+extern char *__bad_type_size(void);
+
 #undef FIELD
 #define FIELD(type, name)                                              \
+       sizeof(type) != sizeof(field.name) ? __bad_type_size() :        \
        #type, "common_" #name, offsetof(typeof(field), name),          \
                sizeof(field.name)
 
@@ -391,7 +526,7 @@ static int trace_write_header(struct trace_seq *s)
                                "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
                                "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
                                "\n",
-                               FIELD(unsigned char, type),
+                               FIELD(unsigned short, type),
                                FIELD(unsigned char, flags),
                                FIELD(unsigned char, preempt_count),
                                FIELD(int, pid),
@@ -481,7 +616,7 @@ event_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
 
        trace_seq_init(s);
 
-       filter_print_preds(call->preds, s);
+       print_event_filter(call, s);
        r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
 
        kfree(s);
@@ -494,38 +629,26 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
                   loff_t *ppos)
 {
        struct ftrace_event_call *call = filp->private_data;
-       char buf[64], *pbuf = buf;
-       struct filter_pred *pred;
+       char *buf;
        int err;
 
-       if (cnt >= sizeof(buf))
+       if (cnt >= PAGE_SIZE)
                return -EINVAL;
 
-       if (copy_from_user(&buf, ubuf, cnt))
-               return -EFAULT;
-       buf[cnt] = '\0';
-
-       pred = kzalloc(sizeof(*pred), GFP_KERNEL);
-       if (!pred)
+       buf = (char *)__get_free_page(GFP_TEMPORARY);
+       if (!buf)
                return -ENOMEM;
 
-       err = filter_parse(&pbuf, pred);
-       if (err < 0) {
-               filter_free_pred(pred);
-               return err;
-       }
-
-       if (pred->clear) {
-               filter_free_preds(call);
-               filter_free_pred(pred);
-               return cnt;
+       if (copy_from_user(buf, ubuf, cnt)) {
+               free_page((unsigned long) buf);
+               return -EFAULT;
        }
+       buf[cnt] = '\0';
 
-       err = filter_add_pred(call, pred);
-       if (err < 0) {
-               filter_free_pred(pred);
+       err = apply_event_filter(call, buf);
+       free_page((unsigned long) buf);
+       if (err < 0)
                return err;
-       }
 
        *ppos += cnt;
 
@@ -549,7 +672,7 @@ subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
 
        trace_seq_init(s);
 
-       filter_print_preds(system->preds, s);
+       print_subsystem_event_filter(system, s);
        r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
 
        kfree(s);
@@ -562,45 +685,56 @@ subsystem_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
                       loff_t *ppos)
 {
        struct event_subsystem *system = filp->private_data;
-       char buf[64], *pbuf = buf;
-       struct filter_pred *pred;
+       char *buf;
        int err;
 
-       if (cnt >= sizeof(buf))
+       if (cnt >= PAGE_SIZE)
                return -EINVAL;
 
-       if (copy_from_user(&buf, ubuf, cnt))
-               return -EFAULT;
-       buf[cnt] = '\0';
-
-       pred = kzalloc(sizeof(*pred), GFP_KERNEL);
-       if (!pred)
+       buf = (char *)__get_free_page(GFP_TEMPORARY);
+       if (!buf)
                return -ENOMEM;
 
-       err = filter_parse(&pbuf, pred);
-       if (err < 0) {
-               filter_free_pred(pred);
-               return err;
-       }
-
-       if (pred->clear) {
-               filter_free_subsystem_preds(system);
-               filter_free_pred(pred);
-               return cnt;
+       if (copy_from_user(buf, ubuf, cnt)) {
+               free_page((unsigned long) buf);
+               return -EFAULT;
        }
+       buf[cnt] = '\0';
 
-       err = filter_add_subsystem_pred(system, pred);
-       if (err < 0) {
-               filter_free_subsystem_preds(system);
-               filter_free_pred(pred);
+       err = apply_subsystem_event_filter(system, buf);
+       free_page((unsigned long) buf);
+       if (err < 0)
                return err;
-       }
 
        *ppos += cnt;
 
        return cnt;
 }
 
+static ssize_t
+show_header(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+       int (*func)(struct trace_seq *s) = filp->private_data;
+       struct trace_seq *s;
+       int r;
+
+       if (*ppos)
+               return 0;
+
+       s = kmalloc(sizeof(*s), GFP_KERNEL);
+       if (!s)
+               return -ENOMEM;
+
+       trace_seq_init(s);
+
+       func(s);
+       r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
+
+       kfree(s);
+
+       return r;
+}
+
 static const struct seq_operations show_event_seq_ops = {
        .start = t_start,
        .next = t_next,
@@ -658,6 +792,17 @@ static const struct file_operations ftrace_subsystem_filter_fops = {
        .write = subsystem_filter_write,
 };
 
+static const struct file_operations ftrace_system_enable_fops = {
+       .open = tracing_open_generic,
+       .read = system_enable_read,
+       .write = system_enable_write,
+};
+
+static const struct file_operations ftrace_show_header_fops = {
+       .open = tracing_open_generic,
+       .read = show_header,
+};
+
 static struct dentry *event_trace_events_dir(void)
 {
        static struct dentry *d_tracer;
@@ -684,6 +829,7 @@ static struct dentry *
 event_subsystem_dir(const char *name, struct dentry *d_events)
 {
        struct event_subsystem *system;
+       struct dentry *entry;
 
        /* First see if we did not already create this dir */
        list_for_each_entry(system, &event_subsystems, list) {
@@ -707,16 +853,46 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
                return d_events;
        }
 
-       system->name = name;
+       system->name = kstrdup(name, GFP_KERNEL);
+       if (!system->name) {
+               debugfs_remove(system->entry);
+               kfree(system);
+               return d_events;
+       }
+
        list_add(&system->list, &event_subsystems);
 
-       system->preds = NULL;
+       system->filter = NULL;
+
+       system->filter = kzalloc(sizeof(struct event_filter), GFP_KERNEL);
+       if (!system->filter) {
+               pr_warning("Could not allocate filter for subsystem "
+                          "'%s'\n", name);
+               return system->entry;
+       }
+
+       entry = debugfs_create_file("filter", 0644, system->entry, system,
+                                   &ftrace_subsystem_filter_fops);
+       if (!entry) {
+               kfree(system->filter);
+               system->filter = NULL;
+               pr_warning("Could not create debugfs "
+                          "'%s/filter' entry\n", name);
+       }
+
+       entry = trace_create_file("enable", 0644, system->entry,
+                                 (void *)system->name,
+                                 &ftrace_system_enable_fops);
 
        return system->entry;
 }
 
 static int
-event_create_dir(struct ftrace_event_call *call, struct dentry *d_events)
+event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
+                const struct file_operations *id,
+                const struct file_operations *enable,
+                const struct file_operations *filter,
+                const struct file_operations *format)
 {
        struct dentry *entry;
        int ret;
@@ -725,7 +901,7 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events)
         * If the trace point header did not define TRACE_SYSTEM
         * then the system would be called "TRACE_SYSTEM".
         */
-       if (strcmp(call->system, "TRACE_SYSTEM") != 0)
+       if (strcmp(call->system, TRACE_SYSTEM) != 0)
                d_events = event_subsystem_dir(call->system, d_events);
 
        if (call->raw_init) {
@@ -744,21 +920,13 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events)
                return -1;
        }
 
-       if (call->regfunc) {
-               entry = debugfs_create_file("enable", 0644, call->dir, call,
-                                           &ftrace_enable_fops);
-               if (!entry)
-                       pr_warning("Could not create debugfs "
-                                  "'%s/enable' entry\n", call->name);
-       }
+       if (call->regfunc)
+               entry = trace_create_file("enable", 0644, call->dir, call,
+                                         enable);
 
-       if (call->id) {
-               entry = debugfs_create_file("id", 0444, call->dir, call,
-                               &ftrace_event_id_fops);
-               if (!entry)
-                       pr_warning("Could not create debugfs '%s/id' entry\n",
-                                       call->name);
-       }
+       if (call->id)
+               entry = trace_create_file("id", 0444, call->dir, call,
+                                         id);
 
        if (call->define_fields) {
                ret = call->define_fields();
@@ -767,32 +935,195 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events)
                                   " events/%s\n", call->name);
                        return ret;
                }
-               entry = debugfs_create_file("filter", 0644, call->dir, call,
-                                           &ftrace_event_filter_fops);
-               if (!entry)
-                       pr_warning("Could not create debugfs "
-                                  "'%s/filter' entry\n", call->name);
+               entry = trace_create_file("filter", 0644, call->dir, call,
+                                         filter);
        }
 
        /* A trace may not want to export its format */
        if (!call->show_format)
                return 0;
 
-       entry = debugfs_create_file("format", 0444, call->dir, call,
-                                   &ftrace_event_format_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs "
-                          "'%s/format' entry\n", call->name);
+       entry = trace_create_file("format", 0444, call->dir, call,
+                                 format);
+
+       return 0;
+}
+
+#define for_each_event(event, start, end)                      \
+       for (event = start;                                     \
+            (unsigned long)event < (unsigned long)end;         \
+            event++)
+
+#ifdef CONFIG_MODULES
+
+static LIST_HEAD(ftrace_module_file_list);
+
+/*
+ * Modules must own their file_operations to keep up with
+ * reference counting.
+ */
+struct ftrace_module_file_ops {
+       struct list_head                list;
+       struct module                   *mod;
+       struct file_operations          id;
+       struct file_operations          enable;
+       struct file_operations          format;
+       struct file_operations          filter;
+};
+
+static struct ftrace_module_file_ops *
+trace_create_file_ops(struct module *mod)
+{
+       struct ftrace_module_file_ops *file_ops;
+
+       /*
+        * This is a bit of a PITA. To allow for correct reference
+        * counting, modules must "own" their file_operations.
+        * To do this, we allocate the file operations that will be
+        * used in the event directory.
+        */
+
+       file_ops = kmalloc(sizeof(*file_ops), GFP_KERNEL);
+       if (!file_ops)
+               return NULL;
+
+       file_ops->mod = mod;
+
+       file_ops->id = ftrace_event_id_fops;
+       file_ops->id.owner = mod;
+
+       file_ops->enable = ftrace_enable_fops;
+       file_ops->enable.owner = mod;
+
+       file_ops->filter = ftrace_event_filter_fops;
+       file_ops->filter.owner = mod;
+
+       file_ops->format = ftrace_event_format_fops;
+       file_ops->format.owner = mod;
+
+       list_add(&file_ops->list, &ftrace_module_file_list);
+
+       return file_ops;
+}
+
+static void trace_module_add_events(struct module *mod)
+{
+       struct ftrace_module_file_ops *file_ops = NULL;
+       struct ftrace_event_call *call, *start, *end;
+       struct dentry *d_events;
+
+       start = mod->trace_events;
+       end = mod->trace_events + mod->num_trace_events;
+
+       if (start == end)
+               return;
+
+       d_events = event_trace_events_dir();
+       if (!d_events)
+               return;
+
+       for_each_event(call, start, end) {
+               /* The linker may leave blanks */
+               if (!call->name)
+                       continue;
+
+               /*
+                * This module has events, create file ops for this module
+                * if not already done.
+                */
+               if (!file_ops) {
+                       file_ops = trace_create_file_ops(mod);
+                       if (!file_ops)
+                               return;
+               }
+               call->mod = mod;
+               list_add(&call->list, &ftrace_events);
+               event_create_dir(call, d_events,
+                                &file_ops->id, &file_ops->enable,
+                                &file_ops->filter, &file_ops->format);
+       }
+}
+
+static void trace_module_remove_events(struct module *mod)
+{
+       struct ftrace_module_file_ops *file_ops;
+       struct ftrace_event_call *call, *p;
+       bool found = false;
+
+       down_write(&trace_event_mutex);
+       list_for_each_entry_safe(call, p, &ftrace_events, list) {
+               if (call->mod == mod) {
+                       found = true;
+                       ftrace_event_enable_disable(call, 0);
+                       if (call->event)
+                               __unregister_ftrace_event(call->event);
+                       debugfs_remove_recursive(call->dir);
+                       list_del(&call->list);
+                       trace_destroy_fields(call);
+                       destroy_preds(call);
+               }
+       }
+
+       /* Now free the file_operations */
+       list_for_each_entry(file_ops, &ftrace_module_file_list, list) {
+               if (file_ops->mod == mod)
+                       break;
+       }
+       if (&file_ops->list != &ftrace_module_file_list) {
+               list_del(&file_ops->list);
+               kfree(file_ops);
+       }
+
+       /*
+        * It is safest to reset the ring buffer if the module being unloaded
+        * registered any events.
+        */
+       if (found)
+               tracing_reset_current_online_cpus();
+       up_write(&trace_event_mutex);
+}
+
+static int trace_module_notify(struct notifier_block *self,
+                              unsigned long val, void *data)
+{
+       struct module *mod = data;
+
+       mutex_lock(&event_mutex);
+       switch (val) {
+       case MODULE_STATE_COMING:
+               trace_module_add_events(mod);
+               break;
+       case MODULE_STATE_GOING:
+               trace_module_remove_events(mod);
+               break;
+       }
+       mutex_unlock(&event_mutex);
 
        return 0;
 }
+#else
+static int trace_module_notify(struct notifier_block *self,
+                              unsigned long val, void *data)
+{
+       return 0;
+}
+#endif /* CONFIG_MODULES */
+
+struct notifier_block trace_module_nb = {
+       .notifier_call = trace_module_notify,
+       .priority = 0,
+};
+
+extern struct ftrace_event_call __start_ftrace_events[];
+extern struct ftrace_event_call __stop_ftrace_events[];
 
 static __init int event_trace_init(void)
 {
-       struct ftrace_event_call *call = __start_ftrace_events;
+       struct ftrace_event_call *call;
        struct dentry *d_tracer;
        struct dentry *entry;
        struct dentry *d_events;
+       int ret;
 
        d_tracer = tracing_init_dentry();
        if (!d_tracer)
@@ -816,13 +1147,243 @@ static __init int event_trace_init(void)
        if (!d_events)
                return 0;
 
-       for_each_event(call) {
+       /* ring buffer internal formats */
+       trace_create_file("header_page", 0444, d_events,
+                         ring_buffer_print_page_header,
+                         &ftrace_show_header_fops);
+
+       trace_create_file("header_event", 0444, d_events,
+                         ring_buffer_print_entry_header,
+                         &ftrace_show_header_fops);
+
+       trace_create_file("enable", 0644, d_events,
+                         NULL, &ftrace_system_enable_fops);
+
+       for_each_event(call, __start_ftrace_events, __stop_ftrace_events) {
                /* The linker may leave blanks */
                if (!call->name)
                        continue;
-               event_create_dir(call, d_events);
+               list_add(&call->list, &ftrace_events);
+               event_create_dir(call, d_events, &ftrace_event_id_fops,
+                                &ftrace_enable_fops, &ftrace_event_filter_fops,
+                                &ftrace_event_format_fops);
        }
 
+       ret = register_module_notifier(&trace_module_nb);
+       if (ret)
+               pr_warning("Failed to register trace events module notifier\n");
+
        return 0;
 }
 fs_initcall(event_trace_init);
+
+#ifdef CONFIG_FTRACE_STARTUP_TEST
+
+static DEFINE_SPINLOCK(test_spinlock);
+static DEFINE_SPINLOCK(test_spinlock_irq);
+static DEFINE_MUTEX(test_mutex);
+
+static __init void test_work(struct work_struct *dummy)
+{
+       spin_lock(&test_spinlock);
+       spin_lock_irq(&test_spinlock_irq);
+       udelay(1);
+       spin_unlock_irq(&test_spinlock_irq);
+       spin_unlock(&test_spinlock);
+
+       mutex_lock(&test_mutex);
+       msleep(1);
+       mutex_unlock(&test_mutex);
+}
+
+static __init int event_test_thread(void *unused)
+{
+       void *test_malloc;
+
+       test_malloc = kmalloc(1234, GFP_KERNEL);
+       if (!test_malloc)
+               pr_info("failed to kmalloc\n");
+
+       schedule_on_each_cpu(test_work);
+
+       kfree(test_malloc);
+
+       set_current_state(TASK_INTERRUPTIBLE);
+       while (!kthread_should_stop())
+               schedule();
+
+       return 0;
+}
+
+/*
+ * Do various things that may trigger events.
+ */
+static __init void event_test_stuff(void)
+{
+       struct task_struct *test_thread;
+
+       test_thread = kthread_run(event_test_thread, NULL, "test-events");
+       msleep(1);
+       kthread_stop(test_thread);
+}
+
+/*
+ * For every trace event defined, we will test each trace point separately,
+ * and then by groups, and finally all trace points.
+ */
+static __init void event_trace_self_tests(void)
+{
+       struct ftrace_event_call *call;
+       struct event_subsystem *system;
+       int ret;
+
+       pr_info("Running tests on trace events:\n");
+
+       list_for_each_entry(call, &ftrace_events, list) {
+
+               /* Only test those that have a regfunc */
+               if (!call->regfunc)
+                       continue;
+
+               pr_info("Testing event %s: ", call->name);
+
+               /*
+                * If an event is already enabled, someone is using
+                * it and the self test should not be on.
+                */
+               if (call->enabled) {
+                       pr_warning("Enabled event during self test!\n");
+                       WARN_ON_ONCE(1);
+                       continue;
+               }
+
+               ftrace_event_enable_disable(call, 1);
+               event_test_stuff();
+               ftrace_event_enable_disable(call, 0);
+
+               pr_cont("OK\n");
+       }
+
+       /* Now test at the sub system level */
+
+       pr_info("Running tests on trace event systems:\n");
+
+       list_for_each_entry(system, &event_subsystems, list) {
+
+               /* the ftrace system is special, skip it */
+               if (strcmp(system->name, "ftrace") == 0)
+                       continue;
+
+               pr_info("Testing event system %s: ", system->name);
+
+               ret = __ftrace_set_clr_event(NULL, system->name, NULL, 1);
+               if (WARN_ON_ONCE(ret)) {
+                       pr_warning("error enabling system %s\n",
+                                  system->name);
+                       continue;
+               }
+
+               event_test_stuff();
+
+               ret = __ftrace_set_clr_event(NULL, system->name, NULL, 0);
+               if (WARN_ON_ONCE(ret))
+                       pr_warning("error disabling system %s\n",
+                                  system->name);
+
+               pr_cont("OK\n");
+       }
+
+       /* Test with all events enabled */
+
+       pr_info("Running tests on all trace events:\n");
+       pr_info("Testing all events: ");
+
+       ret = __ftrace_set_clr_event(NULL, NULL, NULL, 1);
+       if (WARN_ON_ONCE(ret)) {
+               pr_warning("error enabling all events\n");
+               return;
+       }
+
+       event_test_stuff();
+
+       /* reset sysname */
+       ret = __ftrace_set_clr_event(NULL, NULL, NULL, 0);
+       if (WARN_ON_ONCE(ret)) {
+               pr_warning("error disabling all events\n");
+               return;
+       }
+
+       pr_cont("OK\n");
+}
+
+#ifdef CONFIG_FUNCTION_TRACER
+
+static DEFINE_PER_CPU(atomic_t, test_event_disable);
+
+static void
+function_test_events_call(unsigned long ip, unsigned long parent_ip)
+{
+       struct ring_buffer_event *event;
+       struct ftrace_entry *entry;
+       unsigned long flags;
+       long disabled;
+       int resched;
+       int cpu;
+       int pc;
+
+       pc = preempt_count();
+       resched = ftrace_preempt_disable();
+       cpu = raw_smp_processor_id();
+       disabled = atomic_inc_return(&per_cpu(test_event_disable, cpu));
+
+       if (disabled != 1)
+               goto out;
+
+       local_save_flags(flags);
+
+       event = trace_current_buffer_lock_reserve(TRACE_FN, sizeof(*entry),
+                                                 flags, pc);
+       if (!event)
+               goto out;
+       entry   = ring_buffer_event_data(event);
+       entry->ip                       = ip;
+       entry->parent_ip                = parent_ip;
+
+       trace_nowake_buffer_unlock_commit(event, flags, pc);
+
+ out:
+       atomic_dec(&per_cpu(test_event_disable, cpu));
+       ftrace_preempt_enable(resched);
+}
+
+static struct ftrace_ops trace_ops __initdata  =
+{
+       .func = function_test_events_call,
+};
+
+static __init void event_trace_self_test_with_function(void)
+{
+       register_ftrace_function(&trace_ops);
+       pr_info("Running tests again, along with the function tracer\n");
+       event_trace_self_tests();
+       unregister_ftrace_function(&trace_ops);
+}
+#else
+static __init void event_trace_self_test_with_function(void)
+{
+}
+#endif
+
+static __init int event_trace_self_tests_init(void)
+{
+
+       event_trace_self_tests();
+
+       event_trace_self_test_with_function();
+
+       return 0;
+}
+
+late_initcall(event_trace_self_tests_init);
+
+#endif
index e03cbf1e38f36b306f8eafd2ed2d79837b901a37..db6e54bdb596d90b07fef8fed03520157ecf4390 100644 (file)
 #include <linux/uaccess.h>
 #include <linux/module.h>
 #include <linux/ctype.h>
+#include <linux/mutex.h>
 
 #include "trace.h"
 #include "trace_output.h"
 
-static int filter_pred_64(struct filter_pred *pred, void *event)
+static DEFINE_MUTEX(filter_mutex);
+
+enum filter_op_ids
+{
+       OP_OR,
+       OP_AND,
+       OP_NE,
+       OP_EQ,
+       OP_LT,
+       OP_LE,
+       OP_GT,
+       OP_GE,
+       OP_NONE,
+       OP_OPEN_PAREN,
+};
+
+struct filter_op {
+       int id;
+       char *string;
+       int precedence;
+};
+
+static struct filter_op filter_ops[] = {
+       { OP_OR, "||", 1 },
+       { OP_AND, "&&", 2 },
+       { OP_NE, "!=", 4 },
+       { OP_EQ, "==", 4 },
+       { OP_LT, "<", 5 },
+       { OP_LE, "<=", 5 },
+       { OP_GT, ">", 5 },
+       { OP_GE, ">=", 5 },
+       { OP_NONE, "OP_NONE", 0 },
+       { OP_OPEN_PAREN, "(", 0 },
+};
+
+enum {
+       FILT_ERR_NONE,
+       FILT_ERR_INVALID_OP,
+       FILT_ERR_UNBALANCED_PAREN,
+       FILT_ERR_TOO_MANY_OPERANDS,
+       FILT_ERR_OPERAND_TOO_LONG,
+       FILT_ERR_FIELD_NOT_FOUND,
+       FILT_ERR_ILLEGAL_FIELD_OP,
+       FILT_ERR_ILLEGAL_INTVAL,
+       FILT_ERR_BAD_SUBSYS_FILTER,
+       FILT_ERR_TOO_MANY_PREDS,
+       FILT_ERR_MISSING_FIELD,
+       FILT_ERR_INVALID_FILTER,
+};
+
+static char *err_text[] = {
+       "No error",
+       "Invalid operator",
+       "Unbalanced parens",
+       "Too many operands",
+       "Operand too long",
+       "Field not found",
+       "Illegal operation for field type",
+       "Illegal integer value",
+       "Couldn't find or set field in one of a subsystem's events",
+       "Too many terms in predicate expression",
+       "Missing field name and/or value",
+       "Meaningless filter expression",
+};
+
+struct opstack_op {
+       int op;
+       struct list_head list;
+};
+
+struct postfix_elt {
+       int op;
+       char *operand;
+       struct list_head list;
+};
+
+struct filter_parse_state {
+       struct filter_op *ops;
+       struct list_head opstack;
+       struct list_head postfix;
+       int lasterr;
+       int lasterr_pos;
+
+       struct {
+               char *string;
+               unsigned int cnt;
+               unsigned int tail;
+       } infix;
+
+       struct {
+               char string[MAX_FILTER_STR_VAL];
+               int pos;
+               unsigned int tail;
+       } operand;
+};
+
+DEFINE_COMPARISON_PRED(s64);
+DEFINE_COMPARISON_PRED(u64);
+DEFINE_COMPARISON_PRED(s32);
+DEFINE_COMPARISON_PRED(u32);
+DEFINE_COMPARISON_PRED(s16);
+DEFINE_COMPARISON_PRED(u16);
+DEFINE_COMPARISON_PRED(s8);
+DEFINE_COMPARISON_PRED(u8);
+
+DEFINE_EQUALITY_PRED(64);
+DEFINE_EQUALITY_PRED(32);
+DEFINE_EQUALITY_PRED(16);
+DEFINE_EQUALITY_PRED(8);
+
+static int filter_pred_and(struct filter_pred *pred __attribute((unused)),
+                          void *event __attribute((unused)),
+                          int val1, int val2)
+{
+       return val1 && val2;
+}
+
+static int filter_pred_or(struct filter_pred *pred __attribute((unused)),
+                         void *event __attribute((unused)),
+                         int val1, int val2)
+{
+       return val1 || val2;
+}
+
+/* Filter predicate for fixed sized arrays of characters */
+static int filter_pred_string(struct filter_pred *pred, void *event,
+                             int val1, int val2)
 {
-       u64 *addr = (u64 *)(event + pred->offset);
-       u64 val = (u64)pred->val;
-       int match;
+       char *addr = (char *)(event + pred->offset);
+       int cmp, match;
+
+       cmp = strncmp(addr, pred->str_val, pred->str_len);
 
-       match = (val == *addr) ^ pred->not;
+       match = (!cmp) ^ pred->not;
 
        return match;
 }
 
-static int filter_pred_32(struct filter_pred *pred, void *event)
+/*
+ * Filter predicate for dynamic sized arrays of characters.
+ * These are implemented through a list of strings at the end
+ * of the entry.
+ * Also each of these strings have a field in the entry which
+ * contains its offset from the beginning of the entry.
+ * We have then first to get this field, dereference it
+ * and add it to the address of the entry, and at last we have
+ * the address of the string.
+ */
+static int filter_pred_strloc(struct filter_pred *pred, void *event,
+                             int val1, int val2)
 {
-       u32 *addr = (u32 *)(event + pred->offset);
-       u32 val = (u32)pred->val;
-       int match;
+       int str_loc = *(int *)(event + pred->offset);
+       char *addr = (char *)(event + str_loc);
+       int cmp, match;
+
+       cmp = strncmp(addr, pred->str_val, pred->str_len);
 
-       match = (val == *addr) ^ pred->not;
+       match = (!cmp) ^ pred->not;
 
        return match;
 }
 
-static int filter_pred_16(struct filter_pred *pred, void *event)
+static int filter_pred_none(struct filter_pred *pred, void *event,
+                           int val1, int val2)
+{
+       return 0;
+}
+
+/* return 1 if event matches, 0 otherwise (discard) */
+int filter_match_preds(struct ftrace_event_call *call, void *rec)
 {
-       u16 *addr = (u16 *)(event + pred->offset);
-       u16 val = (u16)pred->val;
-       int match;
+       struct event_filter *filter = call->filter;
+       int match, top = 0, val1 = 0, val2 = 0;
+       int stack[MAX_FILTER_PRED];
+       struct filter_pred *pred;
+       int i;
+
+       for (i = 0; i < filter->n_preds; i++) {
+               pred = filter->preds[i];
+               if (!pred->pop_n) {
+                       match = pred->fn(pred, rec, val1, val2);
+                       stack[top++] = match;
+                       continue;
+               }
+               if (pred->pop_n > top) {
+                       WARN_ON_ONCE(1);
+                       return 0;
+               }
+               val1 = stack[--top];
+               val2 = stack[--top];
+               match = pred->fn(pred, rec, val1, val2);
+               stack[top++] = match;
+       }
 
-       match = (val == *addr) ^ pred->not;
+       return stack[--top];
+}
+EXPORT_SYMBOL_GPL(filter_match_preds);
 
-       return match;
+static void parse_error(struct filter_parse_state *ps, int err, int pos)
+{
+       ps->lasterr = err;
+       ps->lasterr_pos = pos;
 }
 
-static int filter_pred_8(struct filter_pred *pred, void *event)
+static void remove_filter_string(struct event_filter *filter)
 {
-       u8 *addr = (u8 *)(event + pred->offset);
-       u8 val = (u8)pred->val;
-       int match;
+       kfree(filter->filter_string);
+       filter->filter_string = NULL;
+}
 
-       match = (val == *addr) ^ pred->not;
+static int replace_filter_string(struct event_filter *filter,
+                                char *filter_string)
+{
+       kfree(filter->filter_string);
+       filter->filter_string = kstrdup(filter_string, GFP_KERNEL);
+       if (!filter->filter_string)
+               return -ENOMEM;
 
-       return match;
+       return 0;
 }
 
-static int filter_pred_string(struct filter_pred *pred, void *event)
+static int append_filter_string(struct event_filter *filter,
+                               char *string)
 {
-       char *addr = (char *)(event + pred->offset);
-       int cmp, match;
+       int newlen;
+       char *new_filter_string;
 
-       cmp = strncmp(addr, pred->str_val, pred->str_len);
+       BUG_ON(!filter->filter_string);
+       newlen = strlen(filter->filter_string) + strlen(string) + 1;
+       new_filter_string = kmalloc(newlen, GFP_KERNEL);
+       if (!new_filter_string)
+               return -ENOMEM;
 
-       match = (!cmp) ^ pred->not;
+       strcpy(new_filter_string, filter->filter_string);
+       strcat(new_filter_string, string);
+       kfree(filter->filter_string);
+       filter->filter_string = new_filter_string;
 
-       return match;
+       return 0;
 }
 
-/* return 1 if event matches, 0 otherwise (discard) */
-int filter_match_preds(struct ftrace_event_call *call, void *rec)
+static void append_filter_err(struct filter_parse_state *ps,
+                             struct event_filter *filter)
 {
-       int i, matched, and_failed = 0;
-       struct filter_pred *pred;
+       int pos = ps->lasterr_pos;
+       char *buf, *pbuf;
 
-       for (i = 0; i < MAX_FILTER_PRED; i++) {
-               if (call->preds[i]) {
-                       pred = call->preds[i];
-                       if (and_failed && !pred->or)
-                               continue;
-                       matched = pred->fn(pred, rec);
-                       if (!matched && !pred->or) {
-                               and_failed = 1;
-                               continue;
-                       } else if (matched && pred->or)
-                               return 1;
-               } else
-                       break;
-       }
+       buf = (char *)__get_free_page(GFP_TEMPORARY);
+       if (!buf)
+               return;
 
-       if (and_failed)
-               return 0;
+       append_filter_string(filter, "\n");
+       memset(buf, ' ', PAGE_SIZE);
+       if (pos > PAGE_SIZE - 128)
+               pos = 0;
+       buf[pos] = '^';
+       pbuf = &buf[pos] + 1;
 
-       return 1;
+       sprintf(pbuf, "\nparse_error: %s\n", err_text[ps->lasterr]);
+       append_filter_string(filter, buf);
+       free_page((unsigned long) buf);
 }
 
-void filter_print_preds(struct filter_pred **preds, struct trace_seq *s)
+void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s)
 {
-       char *field_name;
-       struct filter_pred *pred;
-       int i;
+       struct event_filter *filter = call->filter;
 
-       if (!preds) {
+       mutex_lock(&filter_mutex);
+       if (filter->filter_string)
+               trace_seq_printf(s, "%s\n", filter->filter_string);
+       else
                trace_seq_printf(s, "none\n");
-               return;
-       }
+       mutex_unlock(&filter_mutex);
+}
 
-       for (i = 0; i < MAX_FILTER_PRED; i++) {
-               if (preds[i]) {
-                       pred = preds[i];
-                       field_name = pred->field_name;
-                       if (i)
-                               trace_seq_printf(s, pred->or ? "|| " : "&& ");
-                       trace_seq_printf(s, "%s ", field_name);
-                       trace_seq_printf(s, pred->not ? "!= " : "== ");
-                       if (pred->str_val)
-                               trace_seq_printf(s, "%s\n", pred->str_val);
-                       else
-                               trace_seq_printf(s, "%llu\n", pred->val);
-               } else
-                       break;
-       }
+void print_subsystem_event_filter(struct event_subsystem *system,
+                                 struct trace_seq *s)
+{
+       struct event_filter *filter = system->filter;
+
+       mutex_lock(&filter_mutex);
+       if (filter->filter_string)
+               trace_seq_printf(s, "%s\n", filter->filter_string);
+       else
+               trace_seq_printf(s, "none\n");
+       mutex_unlock(&filter_mutex);
 }
 
 static struct ftrace_event_field *
@@ -150,284 +328,828 @@ find_event_field(struct ftrace_event_call *call, char *name)
        return NULL;
 }
 
-void filter_free_pred(struct filter_pred *pred)
+static void filter_free_pred(struct filter_pred *pred)
 {
        if (!pred)
                return;
 
        kfree(pred->field_name);
-       kfree(pred->str_val);
        kfree(pred);
 }
 
-void filter_free_preds(struct ftrace_event_call *call)
+static void filter_clear_pred(struct filter_pred *pred)
 {
-       int i;
+       kfree(pred->field_name);
+       pred->field_name = NULL;
+       pred->str_len = 0;
+}
 
-       if (call->preds) {
-               for (i = 0; i < MAX_FILTER_PRED; i++)
-                       filter_free_pred(call->preds[i]);
-               kfree(call->preds);
-               call->preds = NULL;
+static int filter_set_pred(struct filter_pred *dest,
+                          struct filter_pred *src,
+                          filter_pred_fn_t fn)
+{
+       *dest = *src;
+       if (src->field_name) {
+               dest->field_name = kstrdup(src->field_name, GFP_KERNEL);
+               if (!dest->field_name)
+                       return -ENOMEM;
        }
+       dest->fn = fn;
+
+       return 0;
 }
 
-void filter_free_subsystem_preds(struct event_subsystem *system)
+static void filter_disable_preds(struct ftrace_event_call *call)
 {
-       struct ftrace_event_call *call = __start_ftrace_events;
+       struct event_filter *filter = call->filter;
        int i;
 
-       if (system->preds) {
-               for (i = 0; i < MAX_FILTER_PRED; i++)
-                       filter_free_pred(system->preds[i]);
-               kfree(system->preds);
-               system->preds = NULL;
-       }
+       call->filter_active = 0;
+       filter->n_preds = 0;
 
-       events_for_each(call) {
-               if (!call->name || !call->regfunc)
-                       continue;
+       for (i = 0; i < MAX_FILTER_PRED; i++)
+               filter->preds[i]->fn = filter_pred_none;
+}
+
+void destroy_preds(struct ftrace_event_call *call)
+{
+       struct event_filter *filter = call->filter;
+       int i;
 
-               if (!strcmp(call->system, system->name))
-                       filter_free_preds(call);
+       for (i = 0; i < MAX_FILTER_PRED; i++) {
+               if (filter->preds[i])
+                       filter_free_pred(filter->preds[i]);
        }
+       kfree(filter->preds);
+       kfree(filter);
+       call->filter = NULL;
 }
 
-static int __filter_add_pred(struct ftrace_event_call *call,
-                            struct filter_pred *pred)
+int init_preds(struct ftrace_event_call *call)
 {
+       struct event_filter *filter;
+       struct filter_pred *pred;
        int i;
 
-       if (call->preds && !pred->compound)
-               filter_free_preds(call);
+       filter = call->filter = kzalloc(sizeof(*filter), GFP_KERNEL);
+       if (!call->filter)
+               return -ENOMEM;
 
-       if (!call->preds) {
-               call->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
-                                     GFP_KERNEL);
-               if (!call->preds)
-                       return -ENOMEM;
-       }
+       call->filter_active = 0;
+       filter->n_preds = 0;
+
+       filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL);
+       if (!filter->preds)
+               goto oom;
 
        for (i = 0; i < MAX_FILTER_PRED; i++) {
-               if (!call->preds[i]) {
-                       call->preds[i] = pred;
-                       return 0;
+               pred = kzalloc(sizeof(*pred), GFP_KERNEL);
+               if (!pred)
+                       goto oom;
+               pred->fn = filter_pred_none;
+               filter->preds[i] = pred;
+       }
+
+       return 0;
+
+oom:
+       destroy_preds(call);
+
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(init_preds);
+
+static void filter_free_subsystem_preds(struct event_subsystem *system)
+{
+       struct event_filter *filter = system->filter;
+       struct ftrace_event_call *call;
+       int i;
+
+       if (filter->n_preds) {
+               for (i = 0; i < filter->n_preds; i++)
+                       filter_free_pred(filter->preds[i]);
+               kfree(filter->preds);
+               filter->preds = NULL;
+               filter->n_preds = 0;
+       }
+
+       mutex_lock(&event_mutex);
+       list_for_each_entry(call, &ftrace_events, list) {
+               if (!call->define_fields)
+                       continue;
+
+               if (!strcmp(call->system, system->name)) {
+                       filter_disable_preds(call);
+                       remove_filter_string(call->filter);
                }
        }
+       mutex_unlock(&event_mutex);
+}
+
+static int filter_add_pred_fn(struct filter_parse_state *ps,
+                             struct ftrace_event_call *call,
+                             struct filter_pred *pred,
+                             filter_pred_fn_t fn)
+{
+       struct event_filter *filter = call->filter;
+       int idx, err;
+
+       if (filter->n_preds == MAX_FILTER_PRED) {
+               parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0);
+               return -ENOSPC;
+       }
+
+       idx = filter->n_preds;
+       filter_clear_pred(filter->preds[idx]);
+       err = filter_set_pred(filter->preds[idx], pred, fn);
+       if (err)
+               return err;
 
-       return -ENOSPC;
+       filter->n_preds++;
+       call->filter_active = 1;
+
+       return 0;
 }
 
+enum {
+       FILTER_STATIC_STRING = 1,
+       FILTER_DYN_STRING
+};
+
 static int is_string_field(const char *type)
 {
+       if (strstr(type, "__data_loc") && strstr(type, "char"))
+               return FILTER_DYN_STRING;
+
        if (strchr(type, '[') && strstr(type, "char"))
-               return 1;
+               return FILTER_STATIC_STRING;
 
        return 0;
 }
 
-int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
+static int is_legal_op(struct ftrace_event_field *field, int op)
 {
-       struct ftrace_event_field *field;
-
-       field = find_event_field(call, pred->field_name);
-       if (!field)
-               return -EINVAL;
+       if (is_string_field(field->type) && (op != OP_EQ && op != OP_NE))
+               return 0;
 
-       pred->offset = field->offset;
+       return 1;
+}
 
-       if (is_string_field(field->type)) {
-               if (!pred->str_val)
-                       return -EINVAL;
-               pred->fn = filter_pred_string;
-               pred->str_len = field->size;
-               return __filter_add_pred(call, pred);
-       } else {
-               if (pred->str_val)
-                       return -EINVAL;
-       }
+static filter_pred_fn_t select_comparison_fn(int op, int field_size,
+                                            int field_is_signed)
+{
+       filter_pred_fn_t fn = NULL;
 
-       switch (field->size) {
+       switch (field_size) {
        case 8:
-               pred->fn = filter_pred_64;
+               if (op == OP_EQ || op == OP_NE)
+                       fn = filter_pred_64;
+               else if (field_is_signed)
+                       fn = filter_pred_s64;
+               else
+                       fn = filter_pred_u64;
                break;
        case 4:
-               pred->fn = filter_pred_32;
+               if (op == OP_EQ || op == OP_NE)
+                       fn = filter_pred_32;
+               else if (field_is_signed)
+                       fn = filter_pred_s32;
+               else
+                       fn = filter_pred_u32;
                break;
        case 2:
-               pred->fn = filter_pred_16;
+               if (op == OP_EQ || op == OP_NE)
+                       fn = filter_pred_16;
+               else if (field_is_signed)
+                       fn = filter_pred_s16;
+               else
+                       fn = filter_pred_u16;
                break;
        case 1:
-               pred->fn = filter_pred_8;
+               if (op == OP_EQ || op == OP_NE)
+                       fn = filter_pred_8;
+               else if (field_is_signed)
+                       fn = filter_pred_s8;
+               else
+                       fn = filter_pred_u8;
                break;
-       default:
-               return -EINVAL;
        }
 
-       return __filter_add_pred(call, pred);
+       return fn;
 }
 
-static struct filter_pred *copy_pred(struct filter_pred *pred)
+static int filter_add_pred(struct filter_parse_state *ps,
+                          struct ftrace_event_call *call,
+                          struct filter_pred *pred)
 {
-       struct filter_pred *new_pred = kmalloc(sizeof(*pred), GFP_KERNEL);
-       if (!new_pred)
-               return NULL;
+       struct ftrace_event_field *field;
+       filter_pred_fn_t fn;
+       unsigned long long val;
+       int string_type;
+
+       pred->fn = filter_pred_none;
+
+       if (pred->op == OP_AND) {
+               pred->pop_n = 2;
+               return filter_add_pred_fn(ps, call, pred, filter_pred_and);
+       } else if (pred->op == OP_OR) {
+               pred->pop_n = 2;
+               return filter_add_pred_fn(ps, call, pred, filter_pred_or);
+       }
+
+       field = find_event_field(call, pred->field_name);
+       if (!field) {
+               parse_error(ps, FILT_ERR_FIELD_NOT_FOUND, 0);
+               return -EINVAL;
+       }
 
-       memcpy(new_pred, pred, sizeof(*pred));
+       pred->offset = field->offset;
 
-       if (pred->field_name) {
-               new_pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
-               if (!new_pred->field_name) {
-                       kfree(new_pred);
-                       return NULL;
-               }
+       if (!is_legal_op(field, pred->op)) {
+               parse_error(ps, FILT_ERR_ILLEGAL_FIELD_OP, 0);
+               return -EINVAL;
        }
 
-       if (pred->str_val) {
-               new_pred->str_val = kstrdup(pred->str_val, GFP_KERNEL);
-               if (!new_pred->str_val) {
-                       filter_free_pred(new_pred);
-                       return NULL;
+       string_type = is_string_field(field->type);
+       if (string_type) {
+               if (string_type == FILTER_STATIC_STRING)
+                       fn = filter_pred_string;
+               else
+                       fn = filter_pred_strloc;
+               pred->str_len = field->size;
+               if (pred->op == OP_NE)
+                       pred->not = 1;
+               return filter_add_pred_fn(ps, call, pred, fn);
+       } else {
+               if (strict_strtoull(pred->str_val, 0, &val)) {
+                       parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0);
+                       return -EINVAL;
                }
+               pred->val = val;
+       }
+
+       fn = select_comparison_fn(pred->op, field->size, field->is_signed);
+       if (!fn) {
+               parse_error(ps, FILT_ERR_INVALID_OP, 0);
+               return -EINVAL;
        }
 
-       return new_pred;
+       if (pred->op == OP_NE)
+               pred->not = 1;
+
+       return filter_add_pred_fn(ps, call, pred, fn);
 }
 
-int filter_add_subsystem_pred(struct event_subsystem *system,
-                             struct filter_pred *pred)
+static int filter_add_subsystem_pred(struct filter_parse_state *ps,
+                                    struct event_subsystem *system,
+                                    struct filter_pred *pred,
+                                    char *filter_string)
 {
-       struct ftrace_event_call *call = __start_ftrace_events;
-       struct filter_pred *event_pred;
-       int i;
-
-       if (system->preds && !pred->compound)
-               filter_free_subsystem_preds(system);
+       struct event_filter *filter = system->filter;
+       struct ftrace_event_call *call;
+       int err = 0;
 
-       if (!system->preds) {
-               system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
+       if (!filter->preds) {
+               filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
                                        GFP_KERNEL);
-               if (!system->preds)
+
+               if (!filter->preds)
                        return -ENOMEM;
        }
 
-       for (i = 0; i < MAX_FILTER_PRED; i++) {
-               if (!system->preds[i]) {
-                       system->preds[i] = pred;
-                       break;
-               }
+       if (filter->n_preds == MAX_FILTER_PRED) {
+               parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0);
+               return -ENOSPC;
        }
 
-       if (i == MAX_FILTER_PRED)
-               return -ENOSPC;
+       filter->preds[filter->n_preds] = pred;
+       filter->n_preds++;
 
-       events_for_each(call) {
-               int err;
+       mutex_lock(&event_mutex);
+       list_for_each_entry(call, &ftrace_events, list) {
 
-               if (!call->name || !call->regfunc)
+               if (!call->define_fields)
                        continue;
 
                if (strcmp(call->system, system->name))
                        continue;
 
-               if (!find_event_field(call, pred->field_name))
-                       continue;
+               err = filter_add_pred(ps, call, pred);
+               if (err) {
+                       mutex_unlock(&event_mutex);
+                       filter_free_subsystem_preds(system);
+                       parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0);
+                       goto out;
+               }
+               replace_filter_string(call->filter, filter_string);
+       }
+       mutex_unlock(&event_mutex);
+out:
+       return err;
+}
 
-               event_pred = copy_pred(pred);
-               if (!event_pred)
-                       goto oom;
+static void parse_init(struct filter_parse_state *ps,
+                      struct filter_op *ops,
+                      char *infix_string)
+{
+       memset(ps, '\0', sizeof(*ps));
 
-               err = filter_add_pred(call, event_pred);
-               if (err)
-                       filter_free_pred(event_pred);
-               if (err == -ENOMEM)
-                       goto oom;
+       ps->infix.string = infix_string;
+       ps->infix.cnt = strlen(infix_string);
+       ps->ops = ops;
+
+       INIT_LIST_HEAD(&ps->opstack);
+       INIT_LIST_HEAD(&ps->postfix);
+}
+
+static char infix_next(struct filter_parse_state *ps)
+{
+       ps->infix.cnt--;
+
+       return ps->infix.string[ps->infix.tail++];
+}
+
+static char infix_peek(struct filter_parse_state *ps)
+{
+       if (ps->infix.tail == strlen(ps->infix.string))
+               return 0;
+
+       return ps->infix.string[ps->infix.tail];
+}
+
+static void infix_advance(struct filter_parse_state *ps)
+{
+       ps->infix.cnt--;
+       ps->infix.tail++;
+}
+
+static inline int is_precedence_lower(struct filter_parse_state *ps,
+                                     int a, int b)
+{
+       return ps->ops[a].precedence < ps->ops[b].precedence;
+}
+
+static inline int is_op_char(struct filter_parse_state *ps, char c)
+{
+       int i;
+
+       for (i = 0; strcmp(ps->ops[i].string, "OP_NONE"); i++) {
+               if (ps->ops[i].string[0] == c)
+                       return 1;
        }
 
        return 0;
+}
 
-oom:
-       system->preds[i] = NULL;
-       return -ENOMEM;
+static int infix_get_op(struct filter_parse_state *ps, char firstc)
+{
+       char nextc = infix_peek(ps);
+       char opstr[3];
+       int i;
+
+       opstr[0] = firstc;
+       opstr[1] = nextc;
+       opstr[2] = '\0';
+
+       for (i = 0; strcmp(ps->ops[i].string, "OP_NONE"); i++) {
+               if (!strcmp(opstr, ps->ops[i].string)) {
+                       infix_advance(ps);
+                       return ps->ops[i].id;
+               }
+       }
+
+       opstr[1] = '\0';
+
+       for (i = 0; strcmp(ps->ops[i].string, "OP_NONE"); i++) {
+               if (!strcmp(opstr, ps->ops[i].string))
+                       return ps->ops[i].id;
+       }
+
+       return OP_NONE;
 }
 
-int filter_parse(char **pbuf, struct filter_pred *pred)
+static inline void clear_operand_string(struct filter_parse_state *ps)
 {
-       char *tmp, *tok, *val_str = NULL;
-       int tok_n = 0;
+       memset(ps->operand.string, '\0', MAX_FILTER_STR_VAL);
+       ps->operand.tail = 0;
+}
 
-       /* field ==/!= number, or/and field ==/!= number, number */
-       while ((tok = strsep(pbuf, " \n"))) {
-               if (tok_n == 0) {
-                       if (!strcmp(tok, "0")) {
-                               pred->clear = 1;
-                               return 0;
-                       } else if (!strcmp(tok, "&&")) {
-                               pred->or = 0;
-                               pred->compound = 1;
-                       } else if (!strcmp(tok, "||")) {
-                               pred->or = 1;
-                               pred->compound = 1;
-                       } else
-                               pred->field_name = tok;
-                       tok_n = 1;
+static inline int append_operand_char(struct filter_parse_state *ps, char c)
+{
+       if (ps->operand.tail == MAX_FILTER_STR_VAL - 1)
+               return -EINVAL;
+
+       ps->operand.string[ps->operand.tail++] = c;
+
+       return 0;
+}
+
+static int filter_opstack_push(struct filter_parse_state *ps, int op)
+{
+       struct opstack_op *opstack_op;
+
+       opstack_op = kmalloc(sizeof(*opstack_op), GFP_KERNEL);
+       if (!opstack_op)
+               return -ENOMEM;
+
+       opstack_op->op = op;
+       list_add(&opstack_op->list, &ps->opstack);
+
+       return 0;
+}
+
+static int filter_opstack_empty(struct filter_parse_state *ps)
+{
+       return list_empty(&ps->opstack);
+}
+
+static int filter_opstack_top(struct filter_parse_state *ps)
+{
+       struct opstack_op *opstack_op;
+
+       if (filter_opstack_empty(ps))
+               return OP_NONE;
+
+       opstack_op = list_first_entry(&ps->opstack, struct opstack_op, list);
+
+       return opstack_op->op;
+}
+
+static int filter_opstack_pop(struct filter_parse_state *ps)
+{
+       struct opstack_op *opstack_op;
+       int op;
+
+       if (filter_opstack_empty(ps))
+               return OP_NONE;
+
+       opstack_op = list_first_entry(&ps->opstack, struct opstack_op, list);
+       op = opstack_op->op;
+       list_del(&opstack_op->list);
+
+       kfree(opstack_op);
+
+       return op;
+}
+
+static void filter_opstack_clear(struct filter_parse_state *ps)
+{
+       while (!filter_opstack_empty(ps))
+               filter_opstack_pop(ps);
+}
+
+static char *curr_operand(struct filter_parse_state *ps)
+{
+       return ps->operand.string;
+}
+
+static int postfix_append_operand(struct filter_parse_state *ps, char *operand)
+{
+       struct postfix_elt *elt;
+
+       elt = kmalloc(sizeof(*elt), GFP_KERNEL);
+       if (!elt)
+               return -ENOMEM;
+
+       elt->op = OP_NONE;
+       elt->operand = kstrdup(operand, GFP_KERNEL);
+       if (!elt->operand) {
+               kfree(elt);
+               return -ENOMEM;
+       }
+
+       list_add_tail(&elt->list, &ps->postfix);
+
+       return 0;
+}
+
+static int postfix_append_op(struct filter_parse_state *ps, int op)
+{
+       struct postfix_elt *elt;
+
+       elt = kmalloc(sizeof(*elt), GFP_KERNEL);
+       if (!elt)
+               return -ENOMEM;
+
+       elt->op = op;
+       elt->operand = NULL;
+
+       list_add_tail(&elt->list, &ps->postfix);
+
+       return 0;
+}
+
+static void postfix_clear(struct filter_parse_state *ps)
+{
+       struct postfix_elt *elt;
+
+       while (!list_empty(&ps->postfix)) {
+               elt = list_first_entry(&ps->postfix, struct postfix_elt, list);
+               kfree(elt->operand);
+               list_del(&elt->list);
+       }
+}
+
+static int filter_parse(struct filter_parse_state *ps)
+{
+       int in_string = 0;
+       int op, top_op;
+       char ch;
+
+       while ((ch = infix_next(ps))) {
+               if (ch == '"') {
+                       in_string ^= 1;
                        continue;
                }
-               if (tok_n == 1) {
-                       if (!pred->field_name)
-                               pred->field_name = tok;
-                       else if (!strcmp(tok, "!="))
-                               pred->not = 1;
-                       else if (!strcmp(tok, "=="))
-                               pred->not = 0;
-                       else {
-                               pred->field_name = NULL;
+
+               if (in_string)
+                       goto parse_operand;
+
+               if (isspace(ch))
+                       continue;
+
+               if (is_op_char(ps, ch)) {
+                       op = infix_get_op(ps, ch);
+                       if (op == OP_NONE) {
+                               parse_error(ps, FILT_ERR_INVALID_OP, 0);
                                return -EINVAL;
                        }
-                       tok_n = 2;
+
+                       if (strlen(curr_operand(ps))) {
+                               postfix_append_operand(ps, curr_operand(ps));
+                               clear_operand_string(ps);
+                       }
+
+                       while (!filter_opstack_empty(ps)) {
+                               top_op = filter_opstack_top(ps);
+                               if (!is_precedence_lower(ps, top_op, op)) {
+                                       top_op = filter_opstack_pop(ps);
+                                       postfix_append_op(ps, top_op);
+                                       continue;
+                               }
+                               break;
+                       }
+
+                       filter_opstack_push(ps, op);
                        continue;
                }
-               if (tok_n == 2) {
-                       if (pred->compound) {
-                               if (!strcmp(tok, "!="))
-                                       pred->not = 1;
-                               else if (!strcmp(tok, "=="))
-                                       pred->not = 0;
-                               else {
-                                       pred->field_name = NULL;
-                                       return -EINVAL;
-                               }
-                       } else {
-                               val_str = tok;
-                               break; /* done */
+
+               if (ch == '(') {
+                       filter_opstack_push(ps, OP_OPEN_PAREN);
+                       continue;
+               }
+
+               if (ch == ')') {
+                       if (strlen(curr_operand(ps))) {
+                               postfix_append_operand(ps, curr_operand(ps));
+                               clear_operand_string(ps);
+                       }
+
+                       top_op = filter_opstack_pop(ps);
+                       while (top_op != OP_NONE) {
+                               if (top_op == OP_OPEN_PAREN)
+                                       break;
+                               postfix_append_op(ps, top_op);
+                               top_op = filter_opstack_pop(ps);
+                       }
+                       if (top_op == OP_NONE) {
+                               parse_error(ps, FILT_ERR_UNBALANCED_PAREN, 0);
+                               return -EINVAL;
                        }
-                       tok_n = 3;
                        continue;
                }
-               if (tok_n == 3) {
-                       val_str = tok;
-                       break; /* done */
+parse_operand:
+               if (append_operand_char(ps, ch)) {
+                       parse_error(ps, FILT_ERR_OPERAND_TOO_LONG, 0);
+                       return -EINVAL;
                }
        }
 
-       if (!val_str) {
-               pred->field_name = NULL;
-               return -EINVAL;
+       if (strlen(curr_operand(ps)))
+               postfix_append_operand(ps, curr_operand(ps));
+
+       while (!filter_opstack_empty(ps)) {
+               top_op = filter_opstack_pop(ps);
+               if (top_op == OP_NONE)
+                       break;
+               if (top_op == OP_OPEN_PAREN) {
+                       parse_error(ps, FILT_ERR_UNBALANCED_PAREN, 0);
+                       return -EINVAL;
+               }
+               postfix_append_op(ps, top_op);
        }
 
-       pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
-       if (!pred->field_name)
-               return -ENOMEM;
+       return 0;
+}
 
-       pred->val = simple_strtoull(val_str, &tmp, 0);
-       if (tmp == val_str) {
-               pred->str_val = kstrdup(val_str, GFP_KERNEL);
-               if (!pred->str_val)
-                       return -ENOMEM;
-       } else if (*tmp != '\0')
+static struct filter_pred *create_pred(int op, char *operand1, char *operand2)
+{
+       struct filter_pred *pred;
+
+       pred = kzalloc(sizeof(*pred), GFP_KERNEL);
+       if (!pred)
+               return NULL;
+
+       pred->field_name = kstrdup(operand1, GFP_KERNEL);
+       if (!pred->field_name) {
+               kfree(pred);
+               return NULL;
+       }
+
+       strcpy(pred->str_val, operand2);
+       pred->str_len = strlen(operand2);
+
+       pred->op = op;
+
+       return pred;
+}
+
+static struct filter_pred *create_logical_pred(int op)
+{
+       struct filter_pred *pred;
+
+       pred = kzalloc(sizeof(*pred), GFP_KERNEL);
+       if (!pred)
+               return NULL;
+
+       pred->op = op;
+
+       return pred;
+}
+
+static int check_preds(struct filter_parse_state *ps)
+{
+       int n_normal_preds = 0, n_logical_preds = 0;
+       struct postfix_elt *elt;
+
+       list_for_each_entry(elt, &ps->postfix, list) {
+               if (elt->op == OP_NONE)
+                       continue;
+
+               if (elt->op == OP_AND || elt->op == OP_OR) {
+                       n_logical_preds++;
+                       continue;
+               }
+               n_normal_preds++;
+       }
+
+       if (!n_normal_preds || n_logical_preds >= n_normal_preds) {
+               parse_error(ps, FILT_ERR_INVALID_FILTER, 0);
                return -EINVAL;
+       }
 
        return 0;
 }
 
+static int replace_preds(struct event_subsystem *system,
+                        struct ftrace_event_call *call,
+                        struct filter_parse_state *ps,
+                        char *filter_string)
+{
+       char *operand1 = NULL, *operand2 = NULL;
+       struct filter_pred *pred;
+       struct postfix_elt *elt;
+       int err;
+
+       err = check_preds(ps);
+       if (err)
+               return err;
+
+       list_for_each_entry(elt, &ps->postfix, list) {
+               if (elt->op == OP_NONE) {
+                       if (!operand1)
+                               operand1 = elt->operand;
+                       else if (!operand2)
+                               operand2 = elt->operand;
+                       else {
+                               parse_error(ps, FILT_ERR_TOO_MANY_OPERANDS, 0);
+                               return -EINVAL;
+                       }
+                       continue;
+               }
+
+               if (elt->op == OP_AND || elt->op == OP_OR) {
+                       pred = create_logical_pred(elt->op);
+                       if (call) {
+                               err = filter_add_pred(ps, call, pred);
+                               filter_free_pred(pred);
+                       } else
+                               err = filter_add_subsystem_pred(ps, system,
+                                                       pred, filter_string);
+                       if (err)
+                               return err;
+
+                       operand1 = operand2 = NULL;
+                       continue;
+               }
+
+               if (!operand1 || !operand2) {
+                       parse_error(ps, FILT_ERR_MISSING_FIELD, 0);
+                       return -EINVAL;
+               }
+
+               pred = create_pred(elt->op, operand1, operand2);
+               if (call) {
+                       err = filter_add_pred(ps, call, pred);
+                       filter_free_pred(pred);
+               } else
+                       err = filter_add_subsystem_pred(ps, system, pred,
+                                                       filter_string);
+               if (err)
+                       return err;
+
+               operand1 = operand2 = NULL;
+       }
+
+       return 0;
+}
+
+int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
+{
+       int err;
+
+       struct filter_parse_state *ps;
+
+       mutex_lock(&filter_mutex);
+
+       if (!strcmp(strstrip(filter_string), "0")) {
+               filter_disable_preds(call);
+               remove_filter_string(call->filter);
+               mutex_unlock(&filter_mutex);
+               return 0;
+       }
+
+       err = -ENOMEM;
+       ps = kzalloc(sizeof(*ps), GFP_KERNEL);
+       if (!ps)
+               goto out_unlock;
+
+       filter_disable_preds(call);
+       replace_filter_string(call->filter, filter_string);
+
+       parse_init(ps, filter_ops, filter_string);
+       err = filter_parse(ps);
+       if (err) {
+               append_filter_err(ps, call->filter);
+               goto out;
+       }
+
+       err = replace_preds(NULL, call, ps, filter_string);
+       if (err)
+               append_filter_err(ps, call->filter);
+
+out:
+       filter_opstack_clear(ps);
+       postfix_clear(ps);
+       kfree(ps);
+out_unlock:
+       mutex_unlock(&filter_mutex);
+
+       return err;
+}
+
+int apply_subsystem_event_filter(struct event_subsystem *system,
+                                char *filter_string)
+{
+       int err;
+
+       struct filter_parse_state *ps;
+
+       mutex_lock(&filter_mutex);
+
+       if (!strcmp(strstrip(filter_string), "0")) {
+               filter_free_subsystem_preds(system);
+               remove_filter_string(system->filter);
+               mutex_unlock(&filter_mutex);
+               return 0;
+       }
+
+       err = -ENOMEM;
+       ps = kzalloc(sizeof(*ps), GFP_KERNEL);
+       if (!ps)
+               goto out_unlock;
+
+       filter_free_subsystem_preds(system);
+       replace_filter_string(system->filter, filter_string);
+
+       parse_init(ps, filter_ops, filter_string);
+       err = filter_parse(ps);
+       if (err) {
+               append_filter_err(ps, system->filter);
+               goto out;
+       }
+
+       err = replace_preds(system, NULL, ps, filter_string);
+       if (err)
+               append_filter_err(ps, system->filter);
+
+out:
+       filter_opstack_clear(ps);
+       postfix_clear(ps);
+       kfree(ps);
+out_unlock:
+       mutex_unlock(&filter_mutex);
+
+       return err;
+}
 
diff --git a/kernel/trace/trace_events_stage_1.h b/kernel/trace/trace_events_stage_1.h
deleted file mode 100644 (file)
index 38985f9..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Stage 1 of the trace events.
- *
- * Override the macros in <trace/trace_event_types.h> to include the following:
- *
- * struct ftrace_raw_<call> {
- *     struct trace_entry              ent;
- *     <type>                          <item>;
- *     <type2>                         <item2>[<len>];
- *     [...]
- * };
- *
- * The <type> <item> is created by the __field(type, item) macro or
- * the __array(type2, item2, len) macro.
- * We simply do "type item;", and that will create the fields
- * in the structure.
- */
-
-#undef TRACE_FORMAT
-#define TRACE_FORMAT(call, proto, args, fmt)
-
-#undef __array
-#define __array(type, item, len)       type    item[len];
-
-#undef __field
-#define __field(type, item)            type    item;
-
-#undef TP_STRUCT__entry
-#define TP_STRUCT__entry(args...) args
-
-#undef TRACE_EVENT
-#define TRACE_EVENT(name, proto, args, tstruct, assign, print) \
-       struct ftrace_raw_##name {                              \
-               struct trace_entry      ent;                    \
-               tstruct                                         \
-       };                                                      \
-       static struct ftrace_event_call event_##name
-
-#include <trace/trace_event_types.h>
diff --git a/kernel/trace/trace_events_stage_2.h b/kernel/trace/trace_events_stage_2.h
deleted file mode 100644 (file)
index d363c66..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Stage 2 of the trace events.
- *
- * Override the macros in <trace/trace_event_types.h> to include the following:
- *
- * enum print_line_t
- * ftrace_raw_output_<call>(struct trace_iterator *iter, int flags)
- * {
- *     struct trace_seq *s = &iter->seq;
- *     struct ftrace_raw_<call> *field; <-- defined in stage 1
- *     struct trace_entry *entry;
- *     int ret;
- *
- *     entry = iter->ent;
- *
- *     if (entry->type != event_<call>.id) {
- *             WARN_ON_ONCE(1);
- *             return TRACE_TYPE_UNHANDLED;
- *     }
- *
- *     field = (typeof(field))entry;
- *
- *     ret = trace_seq_printf(s, <TP_printk> "\n");
- *     if (!ret)
- *             return TRACE_TYPE_PARTIAL_LINE;
- *
- *     return TRACE_TYPE_HANDLED;
- * }
- *
- * This is the method used to print the raw event to the trace
- * output format. Note, this is not needed if the data is read
- * in binary.
- */
-
-#undef __entry
-#define __entry field
-
-#undef TP_printk
-#define TP_printk(fmt, args...) fmt "\n", args
-
-#undef TRACE_EVENT
-#define TRACE_EVENT(call, proto, args, tstruct, assign, print)         \
-enum print_line_t                                                      \
-ftrace_raw_output_##call(struct trace_iterator *iter, int flags)       \
-{                                                                      \
-       struct trace_seq *s = &iter->seq;                               \
-       struct ftrace_raw_##call *field;                                \
-       struct trace_entry *entry;                                      \
-       int ret;                                                        \
-                                                                       \
-       entry = iter->ent;                                              \
-                                                                       \
-       if (entry->type != event_##call.id) {                           \
-               WARN_ON_ONCE(1);                                        \
-               return TRACE_TYPE_UNHANDLED;                            \
-       }                                                               \
-                                                                       \
-       field = (typeof(field))entry;                                   \
-                                                                       \
-       ret = trace_seq_printf(s, #call ": " print);                    \
-       if (!ret)                                                       \
-               return TRACE_TYPE_PARTIAL_LINE;                         \
-                                                                       \
-       return TRACE_TYPE_HANDLED;                                      \
-}
-       
-#include <trace/trace_event_types.h>
-
-/*
- * Setup the showing format of trace point.
- *
- * int
- * ftrace_format_##call(struct trace_seq *s)
- * {
- *     struct ftrace_raw_##call field;
- *     int ret;
- *
- *     ret = trace_seq_printf(s, #type " " #item ";"
- *                            " offset:%u; size:%u;\n",
- *                            offsetof(struct ftrace_raw_##call, item),
- *                            sizeof(field.type));
- *
- * }
- */
-
-#undef TP_STRUCT__entry
-#define TP_STRUCT__entry(args...) args
-
-#undef __field
-#define __field(type, item)                                    \
-       ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t"      \
-                              "offset:%u;\tsize:%u;\n",                \
-                              (unsigned int)offsetof(typeof(field), item), \
-                              (unsigned int)sizeof(field.item));       \
-       if (!ret)                                                       \
-               return 0;
-
-#undef __array
-#define __array(type, item, len)                                               \
-       ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t"    \
-                              "offset:%u;\tsize:%u;\n",                \
-                              (unsigned int)offsetof(typeof(field), item), \
-                              (unsigned int)sizeof(field.item));       \
-       if (!ret)                                                       \
-               return 0;
-
-#undef __entry
-#define __entry REC
-
-#undef TP_printk
-#define TP_printk(fmt, args...) "%s, %s\n", #fmt, __stringify(args)
-
-#undef TP_fast_assign
-#define TP_fast_assign(args...) args
-
-#undef TRACE_EVENT
-#define TRACE_EVENT(call, proto, args, tstruct, func, print)           \
-static int                                                             \
-ftrace_format_##call(struct trace_seq *s)                              \
-{                                                                      \
-       struct ftrace_raw_##call field;                                 \
-       int ret;                                                        \
-                                                                       \
-       tstruct;                                                        \
-                                                                       \
-       trace_seq_printf(s, "\nprint fmt: " print);                     \
-                                                                       \
-       return ret;                                                     \
-}
-
-#include <trace/trace_event_types.h>
-
-#undef __field
-#define __field(type, item)                                            \
-       ret = trace_define_field(event_call, #type, #item,              \
-                                offsetof(typeof(field), item),         \
-                                sizeof(field.item));                   \
-       if (ret)                                                        \
-               return ret;
-
-#undef __array
-#define __array(type, item, len)                                       \
-       ret = trace_define_field(event_call, #type "[" #len "]", #item, \
-                                offsetof(typeof(field), item),         \
-                                sizeof(field.item));                   \
-       if (ret)                                                        \
-               return ret;
-
-#define __common_field(type, item)                                     \
-       ret = trace_define_field(event_call, #type, "common_" #item,    \
-                                offsetof(typeof(field.ent), item),     \
-                                sizeof(field.ent.item));               \
-       if (ret)                                                        \
-               return ret;
-
-#undef TRACE_EVENT
-#define TRACE_EVENT(call, proto, args, tstruct, func, print)           \
-int                                                                    \
-ftrace_define_fields_##call(void)                                      \
-{                                                                      \
-       struct ftrace_raw_##call field;                                 \
-       struct ftrace_event_call *event_call = &event_##call;           \
-       int ret;                                                        \
-                                                                       \
-       __common_field(unsigned char, type);                            \
-       __common_field(unsigned char, flags);                           \
-       __common_field(unsigned char, preempt_count);                   \
-       __common_field(int, pid);                                       \
-       __common_field(int, tgid);                                      \
-                                                                       \
-       tstruct;                                                        \
-                                                                       \
-       return ret;                                                     \
-}
-
-#include <trace/trace_event_types.h>
diff --git a/kernel/trace/trace_events_stage_3.h b/kernel/trace/trace_events_stage_3.h
deleted file mode 100644 (file)
index 9d2fa78..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Stage 3 of the trace events.
- *
- * Override the macros in <trace/trace_event_types.h> to include the following:
- *
- * static void ftrace_event_<call>(proto)
- * {
- *     event_trace_printk(_RET_IP_, "<call>: " <fmt>);
- * }
- *
- * static int ftrace_reg_event_<call>(void)
- * {
- *     int ret;
- *
- *     ret = register_trace_<call>(ftrace_event_<call>);
- *     if (!ret)
- *             pr_info("event trace: Could not activate trace point "
- *                     "probe to  <call>");
- *     return ret;
- * }
- *
- * static void ftrace_unreg_event_<call>(void)
- * {
- *     unregister_trace_<call>(ftrace_event_<call>);
- * }
- *
- * For those macros defined with TRACE_FORMAT:
- *
- * static struct ftrace_event_call __used
- * __attribute__((__aligned__(4)))
- * __attribute__((section("_ftrace_events"))) event_<call> = {
- *     .name                   = "<call>",
- *     .regfunc                = ftrace_reg_event_<call>,
- *     .unregfunc              = ftrace_unreg_event_<call>,
- * }
- *
- *
- * For those macros defined with TRACE_EVENT:
- *
- * static struct ftrace_event_call event_<call>;
- *
- * static void ftrace_raw_event_<call>(proto)
- * {
- *     struct ring_buffer_event *event;
- *     struct ftrace_raw_<call> *entry; <-- defined in stage 1
- *     unsigned long irq_flags;
- *     int pc;
- *
- *     local_save_flags(irq_flags);
- *     pc = preempt_count();
- *
- *     event = trace_current_buffer_lock_reserve(event_<call>.id,
- *                               sizeof(struct ftrace_raw_<call>),
- *                               irq_flags, pc);
- *     if (!event)
- *             return;
- *     entry   = ring_buffer_event_data(event);
- *
- *     <assign>;  <-- Here we assign the entries by the __field and
- *                     __array macros.
- *
- *     trace_current_buffer_unlock_commit(event, irq_flags, pc);
- * }
- *
- * static int ftrace_raw_reg_event_<call>(void)
- * {
- *     int ret;
- *
- *     ret = register_trace_<call>(ftrace_raw_event_<call>);
- *     if (!ret)
- *             pr_info("event trace: Could not activate trace point "
- *                     "probe to <call>");
- *     return ret;
- * }
- *
- * static void ftrace_unreg_event_<call>(void)
- * {
- *     unregister_trace_<call>(ftrace_raw_event_<call>);
- * }
- *
- * static struct trace_event ftrace_event_type_<call> = {
- *     .trace                  = ftrace_raw_output_<call>, <-- stage 2
- * };
- *
- * static int ftrace_raw_init_event_<call>(void)
- * {
- *     int id;
- *
- *     id = register_ftrace_event(&ftrace_event_type_<call>);
- *     if (!id)
- *             return -ENODEV;
- *     event_<call>.id = id;
- *     return 0;
- * }
- *
- * static struct ftrace_event_call __used
- * __attribute__((__aligned__(4)))
- * __attribute__((section("_ftrace_events"))) event_<call> = {
- *     .name                   = "<call>",
- *     .system                 = "<system>",
- *     .raw_init               = ftrace_raw_init_event_<call>,
- *     .regfunc                = ftrace_reg_event_<call>,
- *     .unregfunc              = ftrace_unreg_event_<call>,
- *     .show_format            = ftrace_format_<call>,
- * }
- *
- */
-
-#undef TP_FMT
-#define TP_FMT(fmt, args...)   fmt "\n", ##args
-
-#ifdef CONFIG_EVENT_PROFILE
-#define _TRACE_PROFILE(call, proto, args)                              \
-static void ftrace_profile_##call(proto)                               \
-{                                                                      \
-       extern void perf_tpcounter_event(int);                          \
-       perf_tpcounter_event(event_##call.id);                          \
-}                                                                      \
-                                                                       \
-static int ftrace_profile_enable_##call(struct ftrace_event_call *call) \
-{                                                                      \
-       int ret = 0;                                                    \
-                                                                       \
-       if (!atomic_inc_return(&call->profile_count))                   \
-               ret = register_trace_##call(ftrace_profile_##call);     \
-                                                                       \
-       return ret;                                                     \
-}                                                                      \
-                                                                       \
-static void ftrace_profile_disable_##call(struct ftrace_event_call *call) \
-{                                                                      \
-       if (atomic_add_negative(-1, &call->profile_count))              \
-               unregister_trace_##call(ftrace_profile_##call);         \
-}
-
-#define _TRACE_PROFILE_INIT(call)                                      \
-       .profile_count = ATOMIC_INIT(-1),                               \
-       .profile_enable = ftrace_profile_enable_##call,                 \
-       .profile_disable = ftrace_profile_disable_##call,
-
-#else
-#define _TRACE_PROFILE(call, proto, args)
-#define _TRACE_PROFILE_INIT(call)
-#endif
-
-#define _TRACE_FORMAT(call, proto, args, fmt)                          \
-static void ftrace_event_##call(proto)                                 \
-{                                                                      \
-       event_trace_printk(_RET_IP_, #call ": " fmt);                   \
-}                                                                      \
-                                                                       \
-static int ftrace_reg_event_##call(void)                               \
-{                                                                      \
-       int ret;                                                        \
-                                                                       \
-       ret = register_trace_##call(ftrace_event_##call);               \
-       if (ret)                                                        \
-               pr_info("event trace: Could not activate trace point "  \
-                       "probe to " #call "\n");                        \
-       return ret;                                                     \
-}                                                                      \
-                                                                       \
-static void ftrace_unreg_event_##call(void)                            \
-{                                                                      \
-       unregister_trace_##call(ftrace_event_##call);                   \
-}                                                                      \
-                                                                       \
-static struct ftrace_event_call event_##call;                          \
-                                                                       \
-static int ftrace_init_event_##call(void)                              \
-{                                                                      \
-       int id;                                                         \
-                                                                       \
-       id = register_ftrace_event(NULL);                               \
-       if (!id)                                                        \
-               return -ENODEV;                                         \
-       event_##call.id = id;                                           \
-       return 0;                                                       \
-}
-
-#undef TRACE_FORMAT
-#define TRACE_FORMAT(call, proto, args, fmt)                           \
-_TRACE_FORMAT(call, PARAMS(proto), PARAMS(args), PARAMS(fmt))          \
-_TRACE_PROFILE(call, PARAMS(proto), PARAMS(args))                      \
-static struct ftrace_event_call __used                                 \
-__attribute__((__aligned__(4)))                                                \
-__attribute__((section("_ftrace_events"))) event_##call = {            \
-       .name                   = #call,                                \
-       .system                 = __stringify(TRACE_SYSTEM),            \
-       .raw_init               = ftrace_init_event_##call,             \
-       .regfunc                = ftrace_reg_event_##call,              \
-       .unregfunc              = ftrace_unreg_event_##call,            \
-       _TRACE_PROFILE_INIT(call)                                       \
-}
-
-#undef __entry
-#define __entry entry
-
-#undef TRACE_EVENT
-#define TRACE_EVENT(call, proto, args, tstruct, assign, print)         \
-_TRACE_PROFILE(call, PARAMS(proto), PARAMS(args))                      \
-                                                                       \
-static struct ftrace_event_call event_##call;                          \
-                                                                       \
-static void ftrace_raw_event_##call(proto)                             \
-{                                                                      \
-       struct ftrace_event_call *call = &event_##call;                 \
-       struct ring_buffer_event *event;                                \
-       struct ftrace_raw_##call *entry;                                \
-       unsigned long irq_flags;                                        \
-       int pc;                                                         \
-                                                                       \
-       local_save_flags(irq_flags);                                    \
-       pc = preempt_count();                                           \
-                                                                       \
-       event = trace_current_buffer_lock_reserve(event_##call.id,      \
-                                 sizeof(struct ftrace_raw_##call),     \
-                                 irq_flags, pc);                       \
-       if (!event)                                                     \
-               return;                                                 \
-       entry   = ring_buffer_event_data(event);                        \
-                                                                       \
-       assign;                                                         \
-                                                                       \
-       if (call->preds && !filter_match_preds(call, entry))            \
-               ring_buffer_event_discard(event);                       \
-                                                                       \
-       trace_nowake_buffer_unlock_commit(event, irq_flags, pc);        \
-                                                                       \
-}                                                                      \
-                                                                       \
-static int ftrace_raw_reg_event_##call(void)                           \
-{                                                                      \
-       int ret;                                                        \
-                                                                       \
-       ret = register_trace_##call(ftrace_raw_event_##call);           \
-       if (ret)                                                        \
-               pr_info("event trace: Could not activate trace point "  \
-                       "probe to " #call "\n");                        \
-       return ret;                                                     \
-}                                                                      \
-                                                                       \
-static void ftrace_raw_unreg_event_##call(void)                                \
-{                                                                      \
-       unregister_trace_##call(ftrace_raw_event_##call);               \
-}                                                                      \
-                                                                       \
-static struct trace_event ftrace_event_type_##call = {                 \
-       .trace                  = ftrace_raw_output_##call,             \
-};                                                                     \
-                                                                       \
-static int ftrace_raw_init_event_##call(void)                          \
-{                                                                      \
-       int id;                                                         \
-                                                                       \
-       id = register_ftrace_event(&ftrace_event_type_##call);          \
-       if (!id)                                                        \
-               return -ENODEV;                                         \
-       event_##call.id = id;                                           \
-       INIT_LIST_HEAD(&event_##call.fields);                           \
-       return 0;                                                       \
-}                                                                      \
-                                                                       \
-static struct ftrace_event_call __used                                 \
-__attribute__((__aligned__(4)))                                                \
-__attribute__((section("_ftrace_events"))) event_##call = {            \
-       .name                   = #call,                                \
-       .system                 = __stringify(TRACE_SYSTEM),            \
-       .raw_init               = ftrace_raw_init_event_##call,         \
-       .regfunc                = ftrace_raw_reg_event_##call,          \
-       .unregfunc              = ftrace_raw_unreg_event_##call,        \
-       .show_format            = ftrace_format_##call,                 \
-       .define_fields          = ftrace_define_fields_##call,          \
-       _TRACE_PROFILE_INIT(call)                                       \
-}
-
-#include <trace/trace_event_types.h>
-
-#undef _TRACE_PROFILE
-#undef _TRACE_PROFILE_INIT
-
index 07a22c33ebf3c31b4d07b7125a9062118ca90490..d06cf898dc86aeb012a5f2e5bb1abed214aa8102 100644 (file)
 #undef TRACE_STRUCT
 #define TRACE_STRUCT(args...) args
 
+extern void __bad_type_size(void);
+
 #undef TRACE_FIELD
 #define TRACE_FIELD(type, item, assign)                                        \
+       if (sizeof(type) != sizeof(field.item))                         \
+               __bad_type_size();                                      \
        ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t"      \
                               "offset:%u;\tsize:%u;\n",                \
                               (unsigned int)offsetof(typeof(field), item), \
@@ -30,7 +34,7 @@
 
 
 #undef TRACE_FIELD_SPECIAL
-#define TRACE_FIELD_SPECIAL(type_item, item, cmd)                      \
+#define TRACE_FIELD_SPECIAL(type_item, item, len, cmd)                 \
        ret = trace_seq_printf(s, "\tfield special:" #type_item ";\t"   \
                               "offset:%u;\tsize:%u;\n",                \
                               (unsigned int)offsetof(typeof(field), item), \
@@ -46,6 +50,9 @@
        if (!ret)                                                       \
                return 0;
 
+#undef TRACE_FIELD_SIGN
+#define TRACE_FIELD_SIGN(type, item, assign, is_signed)        \
+       TRACE_FIELD(type, item, assign)
 
 #undef TP_RAW_FMT
 #define TP_RAW_FMT(args...) args
@@ -65,6 +72,22 @@ ftrace_format_##call(struct trace_seq *s)                            \
        return ret;                                                     \
 }
 
+#undef TRACE_EVENT_FORMAT_NOFILTER
+#define TRACE_EVENT_FORMAT_NOFILTER(call, proto, args, fmt, tstruct,   \
+                                   tpfmt)                              \
+static int                                                             \
+ftrace_format_##call(struct trace_seq *s)                              \
+{                                                                      \
+       struct args field;                                              \
+       int ret;                                                        \
+                                                                       \
+       tstruct;                                                        \
+                                                                       \
+       trace_seq_printf(s, "\nprint fmt: \"%s\"\n", tpfmt);            \
+                                                                       \
+       return ret;                                                     \
+}
+
 #include "trace_event_types.h"
 
 #undef TRACE_ZERO_CHAR
@@ -78,6 +101,10 @@ ftrace_format_##call(struct trace_seq *s)                           \
 #define TRACE_FIELD(type, item, assign)\
        entry->item = assign;
 
+#undef TRACE_FIELD_SIGN
+#define TRACE_FIELD_SIGN(type, item, assign, is_signed)        \
+       TRACE_FIELD(type, item, assign)
+
 #undef TP_CMD
 #define TP_CMD(cmd...) cmd
 
@@ -85,18 +112,95 @@ ftrace_format_##call(struct trace_seq *s)                          \
 #define TRACE_ENTRY    entry
 
 #undef TRACE_FIELD_SPECIAL
-#define TRACE_FIELD_SPECIAL(type_item, item, cmd) \
+#define TRACE_FIELD_SPECIAL(type_item, item, len, cmd) \
        cmd;
 
 #undef TRACE_EVENT_FORMAT
 #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt)     \
+int ftrace_define_fields_##call(void);                                 \
+static int ftrace_raw_init_event_##call(void);                         \
+                                                                       \
+struct ftrace_event_call __used                                                \
+__attribute__((__aligned__(4)))                                                \
+__attribute__((section("_ftrace_events"))) event_##call = {            \
+       .name                   = #call,                                \
+       .id                     = proto,                                \
+       .system                 = __stringify(TRACE_SYSTEM),            \
+       .raw_init               = ftrace_raw_init_event_##call,         \
+       .show_format            = ftrace_format_##call,                 \
+       .define_fields          = ftrace_define_fields_##call,          \
+};                                                                     \
+static int ftrace_raw_init_event_##call(void)                          \
+{                                                                      \
+       INIT_LIST_HEAD(&event_##call.fields);                           \
+       init_preds(&event_##call);                                      \
+       return 0;                                                       \
+}                                                                      \
+
+#undef TRACE_EVENT_FORMAT_NOFILTER
+#define TRACE_EVENT_FORMAT_NOFILTER(call, proto, args, fmt, tstruct,   \
+                                   tpfmt)                              \
                                                                        \
-static struct ftrace_event_call __used                                 \
+struct ftrace_event_call __used                                                \
 __attribute__((__aligned__(4)))                                                \
 __attribute__((section("_ftrace_events"))) event_##call = {            \
        .name                   = #call,                                \
        .id                     = proto,                                \
        .system                 = __stringify(TRACE_SYSTEM),            \
        .show_format            = ftrace_format_##call,                 \
+};
+
+#include "trace_event_types.h"
+
+#undef TRACE_FIELD
+#define TRACE_FIELD(type, item, assign)                                        \
+       ret = trace_define_field(event_call, #type, #item,              \
+                                offsetof(typeof(field), item),         \
+                                sizeof(field.item), is_signed_type(type));     \
+       if (ret)                                                        \
+               return ret;
+
+#undef TRACE_FIELD_SPECIAL
+#define TRACE_FIELD_SPECIAL(type, item, len, cmd)                      \
+       ret = trace_define_field(event_call, #type "[" #len "]", #item, \
+                                offsetof(typeof(field), item),         \
+                                sizeof(field.item), 0);                \
+       if (ret)                                                        \
+               return ret;
+
+#undef TRACE_FIELD_SIGN
+#define TRACE_FIELD_SIGN(type, item, assign, is_signed)                        \
+       ret = trace_define_field(event_call, #type, #item,              \
+                                offsetof(typeof(field), item),         \
+                                sizeof(field.item), is_signed);        \
+       if (ret)                                                        \
+               return ret;
+
+#undef TRACE_FIELD_ZERO_CHAR
+#define TRACE_FIELD_ZERO_CHAR(item)
+
+#undef TRACE_EVENT_FORMAT
+#define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt)     \
+int                                                                    \
+ftrace_define_fields_##call(void)                                      \
+{                                                                      \
+       struct ftrace_event_call *event_call = &event_##call;           \
+       struct args field;                                              \
+       int ret;                                                        \
+                                                                       \
+       __common_field(unsigned char, type, 0);                         \
+       __common_field(unsigned char, flags, 0);                        \
+       __common_field(unsigned char, preempt_count, 0);                \
+       __common_field(int, pid, 1);                                    \
+       __common_field(int, tgid, 1);                                   \
+                                                                       \
+       tstruct;                                                        \
+                                                                       \
+       return ret;                                                     \
 }
+
+#undef TRACE_EVENT_FORMAT_NOFILTER
+#define TRACE_EVENT_FORMAT_NOFILTER(call, proto, args, fmt, tstruct,   \
+                                   tpfmt)
+
 #include "trace_event_types.h"
index d28687e7b3a7b36859f1ac48fa1ac62d5e52f456..8b592418d8b28953a28e40c2202a50cb2b40dd37 100644 (file)
@@ -65,6 +65,12 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth)
        if (!current->ret_stack)
                return -EBUSY;
 
+       /*
+        * We must make sure the ret_stack is tested before we read
+        * anything else.
+        */
+       smp_rmb();
+
        /* The return trace stack is full */
        if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
                atomic_inc(&current->trace_overrun);
@@ -78,13 +84,14 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth)
        current->ret_stack[index].ret = ret;
        current->ret_stack[index].func = func;
        current->ret_stack[index].calltime = calltime;
+       current->ret_stack[index].subtime = 0;
        *depth = index;
 
        return 0;
 }
 
 /* Retrieve a function return address to the trace stack on thread info.*/
-void
+static void
 ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
 {
        int index;
@@ -104,9 +111,6 @@ ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
        trace->calltime = current->ret_stack[index].calltime;
        trace->overrun = atomic_read(&current->trace_overrun);
        trace->depth = index;
-       barrier();
-       current->curr_ret_stack--;
-
 }
 
 /*
@@ -121,6 +125,8 @@ unsigned long ftrace_return_to_handler(void)
        ftrace_pop_return_trace(&trace, &ret);
        trace.rettime = trace_clock_local();
        ftrace_graph_return(&trace);
+       barrier();
+       current->curr_ret_stack--;
 
        if (unlikely(!ret)) {
                ftrace_graph_stop();
@@ -426,8 +432,8 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,
        return TRACE_TYPE_HANDLED;
 }
 
-static enum print_line_t
-print_graph_duration(unsigned long long duration, struct trace_seq *s)
+enum print_line_t
+trace_print_graph_duration(unsigned long long duration, struct trace_seq *s)
 {
        unsigned long nsecs_rem = do_div(duration, 1000);
        /* log10(ULONG_MAX) + '\0' */
@@ -464,12 +470,23 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s)
                if (!ret)
                        return TRACE_TYPE_PARTIAL_LINE;
        }
+       return TRACE_TYPE_HANDLED;
+}
+
+static enum print_line_t
+print_graph_duration(unsigned long long duration, struct trace_seq *s)
+{
+       int ret;
+
+       ret = trace_print_graph_duration(duration, s);
+       if (ret != TRACE_TYPE_HANDLED)
+               return ret;
 
        ret = trace_seq_printf(s, "|  ");
        if (!ret)
                return TRACE_TYPE_PARTIAL_LINE;
-       return TRACE_TYPE_HANDLED;
 
+       return TRACE_TYPE_HANDLED;
 }
 
 /* Case of a leaf function on its call entry */
index 7bfdf4c2347f38251acb30e6d3ef3ad588c89e30..ca7d7c4d0c2aef41b74585996001d993ff4505e2 100644 (file)
@@ -1,10 +1,9 @@
 /*
- * h/w branch tracer for x86 based on bts
+ * h/w branch tracer for x86 based on BTS
  *
  * Copyright (C) 2008-2009 Intel Corporation.
  * Markus Metzger <markus.t.metzger@gmail.com>, 2008-2009
  */
-#include <linux/spinlock.h>
 #include <linux/kallsyms.h>
 #include <linux/debugfs.h>
 #include <linux/ftrace.h>
 
 #include <asm/ds.h>
 
-#include "trace.h"
 #include "trace_output.h"
+#include "trace.h"
 
 
-#define SIZEOF_BTS (1 << 13)
+#define BTS_BUFFER_SIZE (1 << 13)
 
-/*
- * The tracer lock protects the below per-cpu tracer array.
- * It needs to be held to:
- * - start tracing on all cpus
- * - stop tracing on all cpus
- * - start tracing on a single hotplug cpu
- * - stop tracing on a single hotplug cpu
- * - read the trace from all cpus
- * - read the trace from a single cpu
- */
-static DEFINE_SPINLOCK(bts_tracer_lock);
 static DEFINE_PER_CPU(struct bts_tracer *, tracer);
-static DEFINE_PER_CPU(unsigned char[SIZEOF_BTS], buffer);
+static DEFINE_PER_CPU(unsigned char[BTS_BUFFER_SIZE], buffer);
 
 #define this_tracer per_cpu(tracer, smp_processor_id())
-#define this_buffer per_cpu(buffer, smp_processor_id())
 
-static int __read_mostly trace_hw_branches_enabled;
+static int trace_hw_branches_enabled __read_mostly;
+static int trace_hw_branches_suspended __read_mostly;
 static struct trace_array *hw_branch_trace __read_mostly;
 
 
-/*
- * Start tracing on the current cpu.
- * The argument is ignored.
- *
- * pre: bts_tracer_lock must be locked.
- */
-static void bts_trace_start_cpu(void *arg)
+static void bts_trace_init_cpu(int cpu)
 {
-       if (this_tracer)
-               ds_release_bts(this_tracer);
-
-       this_tracer =
-               ds_request_bts(/* task = */ NULL, this_buffer, SIZEOF_BTS,
-                              /* ovfl = */ NULL, /* th = */ (size_t)-1,
-                              BTS_KERNEL);
-       if (IS_ERR(this_tracer)) {
-               this_tracer = NULL;
-               return;
-       }
+       per_cpu(tracer, cpu) =
+               ds_request_bts_cpu(cpu, per_cpu(buffer, cpu), BTS_BUFFER_SIZE,
+                                  NULL, (size_t)-1, BTS_KERNEL);
+
+       if (IS_ERR(per_cpu(tracer, cpu)))
+               per_cpu(tracer, cpu) = NULL;
 }
 
-static void bts_trace_start(struct trace_array *tr)
+static int bts_trace_init(struct trace_array *tr)
 {
-       spin_lock(&bts_tracer_lock);
+       int cpu;
+
+       hw_branch_trace = tr;
+       trace_hw_branches_enabled = 0;
 
-       on_each_cpu(bts_trace_start_cpu, NULL, 1);
-       trace_hw_branches_enabled = 1;
+       get_online_cpus();
+       for_each_online_cpu(cpu) {
+               bts_trace_init_cpu(cpu);
 
-       spin_unlock(&bts_tracer_lock);
+               if (likely(per_cpu(tracer, cpu)))
+                       trace_hw_branches_enabled = 1;
+       }
+       trace_hw_branches_suspended = 0;
+       put_online_cpus();
+
+       /* If we could not enable tracing on a single cpu, we fail. */
+       return trace_hw_branches_enabled ? 0 : -EOPNOTSUPP;
 }
 
-/*
- * Stop tracing on the current cpu.
- * The argument is ignored.
- *
- * pre: bts_tracer_lock must be locked.
- */
-static void bts_trace_stop_cpu(void *arg)
+static void bts_trace_reset(struct trace_array *tr)
 {
-       if (this_tracer) {
-               ds_release_bts(this_tracer);
-               this_tracer = NULL;
+       int cpu;
+
+       get_online_cpus();
+       for_each_online_cpu(cpu) {
+               if (likely(per_cpu(tracer, cpu))) {
+                       ds_release_bts(per_cpu(tracer, cpu));
+                       per_cpu(tracer, cpu) = NULL;
+               }
        }
+       trace_hw_branches_enabled = 0;
+       trace_hw_branches_suspended = 0;
+       put_online_cpus();
 }
 
-static void bts_trace_stop(struct trace_array *tr)
+static void bts_trace_start(struct trace_array *tr)
 {
-       spin_lock(&bts_tracer_lock);
+       int cpu;
 
-       trace_hw_branches_enabled = 0;
-       on_each_cpu(bts_trace_stop_cpu, NULL, 1);
+       get_online_cpus();
+       for_each_online_cpu(cpu)
+               if (likely(per_cpu(tracer, cpu)))
+                       ds_resume_bts(per_cpu(tracer, cpu));
+       trace_hw_branches_suspended = 0;
+       put_online_cpus();
+}
 
-       spin_unlock(&bts_tracer_lock);
+static void bts_trace_stop(struct trace_array *tr)
+{
+       int cpu;
+
+       get_online_cpus();
+       for_each_online_cpu(cpu)
+               if (likely(per_cpu(tracer, cpu)))
+                       ds_suspend_bts(per_cpu(tracer, cpu));
+       trace_hw_branches_suspended = 1;
+       put_online_cpus();
 }
 
 static int __cpuinit bts_hotcpu_handler(struct notifier_block *nfb,
                                     unsigned long action, void *hcpu)
 {
-       unsigned int cpu = (unsigned long)hcpu;
-
-       spin_lock(&bts_tracer_lock);
-
-       if (!trace_hw_branches_enabled)
-               goto out;
+       int cpu = (long)hcpu;
 
        switch (action) {
        case CPU_ONLINE:
        case CPU_DOWN_FAILED:
-               smp_call_function_single(cpu, bts_trace_start_cpu, NULL, 1);
+               /* The notification is sent with interrupts enabled. */
+               if (trace_hw_branches_enabled) {
+                       bts_trace_init_cpu(cpu);
+
+                       if (trace_hw_branches_suspended &&
+                           likely(per_cpu(tracer, cpu)))
+                               ds_suspend_bts(per_cpu(tracer, cpu));
+               }
                break;
+
        case CPU_DOWN_PREPARE:
-               smp_call_function_single(cpu, bts_trace_stop_cpu, NULL, 1);
-               break;
+               /* The notification is sent with interrupts enabled. */
+               if (likely(per_cpu(tracer, cpu))) {
+                       ds_release_bts(per_cpu(tracer, cpu));
+                       per_cpu(tracer, cpu) = NULL;
+               }
        }
 
- out:
-       spin_unlock(&bts_tracer_lock);
        return NOTIFY_DONE;
 }
 
@@ -126,20 +134,6 @@ static struct notifier_block bts_hotcpu_notifier __cpuinitdata = {
        .notifier_call = bts_hotcpu_handler
 };
 
-static int bts_trace_init(struct trace_array *tr)
-{
-       hw_branch_trace = tr;
-
-       bts_trace_start(tr);
-
-       return 0;
-}
-
-static void bts_trace_reset(struct trace_array *tr)
-{
-       bts_trace_stop(tr);
-}
-
 static void bts_trace_print_header(struct seq_file *m)
 {
        seq_puts(m, "# CPU#        TO  <-  FROM\n");
@@ -147,10 +141,10 @@ static void bts_trace_print_header(struct seq_file *m)
 
 static enum print_line_t bts_trace_print_line(struct trace_iterator *iter)
 {
+       unsigned long symflags = TRACE_ITER_SYM_OFFSET;
        struct trace_entry *entry = iter->ent;
        struct trace_seq *seq = &iter->seq;
        struct hw_branch_entry *it;
-       unsigned long symflags = TRACE_ITER_SYM_OFFSET;
 
        trace_assign_type(it, entry);
 
@@ -168,6 +162,7 @@ static enum print_line_t bts_trace_print_line(struct trace_iterator *iter)
 
 void trace_hw_branch(u64 from, u64 to)
 {
+       struct ftrace_event_call *call = &event_hw_branch;
        struct trace_array *tr = hw_branch_trace;
        struct ring_buffer_event *event;
        struct hw_branch_entry *entry;
@@ -194,7 +189,8 @@ void trace_hw_branch(u64 from, u64 to)
        entry->ent.type = TRACE_HW_BRANCHES;
        entry->from = from;
        entry->to   = to;
-       trace_buffer_unlock_commit(tr, event, 0, 0);
+       if (!filter_check_discard(call, entry, tr->buffer, event))
+               trace_buffer_unlock_commit(tr, event, 0, 0);
 
  out:
        atomic_dec(&tr->data[cpu]->disabled);
@@ -224,11 +220,11 @@ static void trace_bts_at(const struct bts_trace *trace, void *at)
 /*
  * Collect the trace on the current cpu and write it into the ftrace buffer.
  *
- * pre: bts_tracer_lock must be locked
+ * pre: tracing must be suspended on the current cpu
  */
 static void trace_bts_cpu(void *arg)
 {
-       struct trace_array *tr = (struct trace_array *) arg;
+       struct trace_array *tr = (struct trace_array *)arg;
        const struct bts_trace *trace;
        unsigned char *at;
 
@@ -241,10 +237,9 @@ static void trace_bts_cpu(void *arg)
        if (unlikely(!this_tracer))
                return;
 
-       ds_suspend_bts(this_tracer);
        trace = ds_read_bts(this_tracer);
        if (!trace)
-               goto out;
+               return;
 
        for (at = trace->ds.top; (void *)at < trace->ds.end;
             at += trace->ds.size)
@@ -253,18 +248,27 @@ static void trace_bts_cpu(void *arg)
        for (at = trace->ds.begin; (void *)at < trace->ds.top;
             at += trace->ds.size)
                trace_bts_at(trace, at);
-
-out:
-       ds_resume_bts(this_tracer);
 }
 
 static void trace_bts_prepare(struct trace_iterator *iter)
 {
-       spin_lock(&bts_tracer_lock);
+       int cpu;
 
+       get_online_cpus();
+       for_each_online_cpu(cpu)
+               if (likely(per_cpu(tracer, cpu)))
+                       ds_suspend_bts(per_cpu(tracer, cpu));
+       /*
+        * We need to collect the trace on the respective cpu since ftrace
+        * implicitly adds the record for the current cpu.
+        * Once that is more flexible, we could collect the data from any cpu.
+        */
        on_each_cpu(trace_bts_cpu, iter->tr, 1);
 
-       spin_unlock(&bts_tracer_lock);
+       for_each_online_cpu(cpu)
+               if (likely(per_cpu(tracer, cpu)))
+                       ds_resume_bts(per_cpu(tracer, cpu));
+       put_online_cpus();
 }
 
 static void trace_bts_close(struct trace_iterator *iter)
@@ -274,11 +278,11 @@ static void trace_bts_close(struct trace_iterator *iter)
 
 void trace_hw_branch_oops(void)
 {
-       spin_lock(&bts_tracer_lock);
-
-       trace_bts_cpu(hw_branch_trace);
-
-       spin_unlock(&bts_tracer_lock);
+       if (this_tracer) {
+               ds_suspend_bts_noirq(this_tracer);
+               trace_bts_cpu(hw_branch_trace);
+               ds_resume_bts_noirq(this_tracer);
+       }
 }
 
 struct tracer bts_tracer __read_mostly =
@@ -291,7 +295,10 @@ struct tracer bts_tracer __read_mostly =
        .start          = bts_trace_start,
        .stop           = bts_trace_stop,
        .open           = trace_bts_prepare,
-       .close          = trace_bts_close
+       .close          = trace_bts_close,
+#ifdef CONFIG_FTRACE_SELFTEST
+       .selftest       = trace_selftest_startup_hw_branches,
+#endif /* CONFIG_FTRACE_SELFTEST */
 };
 
 __init static int init_bts_trace(void)
index 8e37fcddd8b49fdaf46e7cc145b4de0382b69b1e..d53b45ed080622933b659ca85774f6b13ae0538e 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/kernel.h>
 #include <linux/mmiotrace.h>
 #include <linux/pci.h>
+#include <linux/time.h>
+
 #include <asm/atomic.h>
 
 #include "trace.h"
@@ -174,7 +176,7 @@ static enum print_line_t mmio_print_rw(struct trace_iterator *iter)
        struct mmiotrace_rw *rw;
        struct trace_seq *s     = &iter->seq;
        unsigned long long t    = ns2usecs(iter->ts);
-       unsigned long usec_rem  = do_div(t, 1000000ULL);
+       unsigned long usec_rem  = do_div(t, USEC_PER_SEC);
        unsigned secs           = (unsigned long)t;
        int ret = 1;
 
@@ -221,7 +223,7 @@ static enum print_line_t mmio_print_map(struct trace_iterator *iter)
        struct mmiotrace_map *m;
        struct trace_seq *s     = &iter->seq;
        unsigned long long t    = ns2usecs(iter->ts);
-       unsigned long usec_rem  = do_div(t, 1000000ULL);
+       unsigned long usec_rem  = do_div(t, USEC_PER_SEC);
        unsigned secs           = (unsigned long)t;
        int ret;
 
index 64b54a59c55b585ff3b979f216ba0451273ee6e4..7938f3ae93e3dbe9d898e037c47027c4908a8d94 100644 (file)
 /* must be a power of 2 */
 #define EVENT_HASHSIZE 128
 
-static DEFINE_MUTEX(trace_event_mutex);
+DECLARE_RWSEM(trace_event_mutex);
+
+DEFINE_PER_CPU(struct trace_seq, ftrace_event_seq);
+EXPORT_PER_CPU_SYMBOL(ftrace_event_seq);
+
 static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly;
 
 static int next_event_type = __TRACE_LAST_TYPE + 1;
 
+void trace_print_seq(struct seq_file *m, struct trace_seq *s)
+{
+       int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len;
+
+       s->buffer[len] = 0;
+       seq_puts(m, s->buffer);
+
+       trace_seq_init(s);
+}
+
 enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter)
 {
        struct trace_seq *s = &iter->seq;
@@ -84,6 +98,39 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
 
        return len;
 }
+EXPORT_SYMBOL_GPL(trace_seq_printf);
+
+/**
+ * trace_seq_vprintf - sequence printing of trace information
+ * @s: trace sequence descriptor
+ * @fmt: printf format string
+ *
+ * The tracer may use either sequence operations or its own
+ * copy to user routines. To simplify formating of a trace
+ * trace_seq_printf is used to store strings into a special
+ * buffer (@s). Then the output may be either used by
+ * the sequencer or pulled into another buffer.
+ */
+int
+trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
+{
+       int len = (PAGE_SIZE - 1) - s->len;
+       int ret;
+
+       if (!len)
+               return 0;
+
+       ret = vsnprintf(s->buffer + s->len, len, fmt, args);
+
+       /* If we can't write it all, don't bother writing anything */
+       if (ret >= len)
+               return 0;
+
+       s->len += ret;
+
+       return len;
+}
+EXPORT_SYMBOL_GPL(trace_seq_vprintf);
 
 int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary)
 {
@@ -201,6 +248,67 @@ int trace_seq_path(struct trace_seq *s, struct path *path)
        return 0;
 }
 
+const char *
+ftrace_print_flags_seq(struct trace_seq *p, const char *delim,
+                      unsigned long flags,
+                      const struct trace_print_flags *flag_array)
+{
+       unsigned long mask;
+       const char *str;
+       const char *ret = p->buffer + p->len;
+       int i;
+
+       for (i = 0;  flag_array[i].name && flags; i++) {
+
+               mask = flag_array[i].mask;
+               if ((flags & mask) != mask)
+                       continue;
+
+               str = flag_array[i].name;
+               flags &= ~mask;
+               if (p->len && delim)
+                       trace_seq_puts(p, delim);
+               trace_seq_puts(p, str);
+       }
+
+       /* check for left over flags */
+       if (flags) {
+               if (p->len && delim)
+                       trace_seq_puts(p, delim);
+               trace_seq_printf(p, "0x%lx", flags);
+       }
+
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+EXPORT_SYMBOL(ftrace_print_flags_seq);
+
+const char *
+ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,
+                        const struct trace_print_flags *symbol_array)
+{
+       int i;
+       const char *ret = p->buffer + p->len;
+
+       for (i = 0;  symbol_array[i].name; i++) {
+
+               if (val != symbol_array[i].mask)
+                       continue;
+
+               trace_seq_puts(p, symbol_array[i].name);
+               break;
+       }
+
+       if (!p->len)
+               trace_seq_printf(p, "0x%lx", val);
+               
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+EXPORT_SYMBOL(ftrace_print_symbols_seq);
+
 #ifdef CONFIG_KRETPROBES
 static inline const char *kretprobed(const char *name)
 {
@@ -311,17 +419,20 @@ seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
 
                if (ip == ULONG_MAX || !ret)
                        break;
-               if (i && ret)
-                       ret = trace_seq_puts(s, " <- ");
+               if (ret)
+                       ret = trace_seq_puts(s, " => ");
                if (!ip) {
                        if (ret)
                                ret = trace_seq_puts(s, "??");
+                       if (ret)
+                               ret = trace_seq_puts(s, "\n");
                        continue;
                }
                if (!ret)
                        break;
                if (ret)
                        ret = seq_print_user_ip(s, mm, ip, sym_flags);
+               ret = trace_seq_puts(s, "\n");
        }
 
        if (mm)
@@ -455,6 +566,7 @@ static int task_state_char(unsigned long state)
  * @type: the type of event to look for
  *
  * Returns an event of type @type otherwise NULL
+ * Called with trace_event_read_lock() held.
  */
 struct trace_event *ftrace_find_event(int type)
 {
@@ -464,7 +576,7 @@ struct trace_event *ftrace_find_event(int type)
 
        key = type & (EVENT_HASHSIZE - 1);
 
-       hlist_for_each_entry_rcu(event, n, &event_hash[key], node) {
+       hlist_for_each_entry(event, n, &event_hash[key], node) {
                if (event->type == type)
                        return event;
        }
@@ -472,6 +584,46 @@ struct trace_event *ftrace_find_event(int type)
        return NULL;
 }
 
+static LIST_HEAD(ftrace_event_list);
+
+static int trace_search_list(struct list_head **list)
+{
+       struct trace_event *e;
+       int last = __TRACE_LAST_TYPE;
+
+       if (list_empty(&ftrace_event_list)) {
+               *list = &ftrace_event_list;
+               return last + 1;
+       }
+
+       /*
+        * We used up all possible max events,
+        * lets see if somebody freed one.
+        */
+       list_for_each_entry(e, &ftrace_event_list, list) {
+               if (e->type != last + 1)
+                       break;
+               last++;
+       }
+
+       /* Did we used up all 65 thousand events??? */
+       if ((last + 1) > FTRACE_MAX_EVENT)
+               return 0;
+
+       *list = &e->list;
+       return last + 1;
+}
+
+void trace_event_read_lock(void)
+{
+       down_read(&trace_event_mutex);
+}
+
+void trace_event_read_unlock(void)
+{
+       up_read(&trace_event_mutex);
+}
+
 /**
  * register_ftrace_event - register output for an event type
  * @event: the event type to register
@@ -492,22 +644,42 @@ int register_ftrace_event(struct trace_event *event)
        unsigned key;
        int ret = 0;
 
-       mutex_lock(&trace_event_mutex);
+       down_write(&trace_event_mutex);
 
-       if (!event) {
-               ret = next_event_type++;
+       if (WARN_ON(!event))
                goto out;
-       }
 
-       if (!event->type)
-               event->type = next_event_type++;
-       else if (event->type > __TRACE_LAST_TYPE) {
+       INIT_LIST_HEAD(&event->list);
+
+       if (!event->type) {
+               struct list_head *list = NULL;
+
+               if (next_event_type > FTRACE_MAX_EVENT) {
+
+                       event->type = trace_search_list(&list);
+                       if (!event->type)
+                               goto out;
+
+               } else {
+                       
+                       event->type = next_event_type++;
+                       list = &ftrace_event_list;
+               }
+
+               if (WARN_ON(ftrace_find_event(event->type)))
+                       goto out;
+
+               list_add_tail(&event->list, list);
+
+       } else if (event->type > __TRACE_LAST_TYPE) {
                printk(KERN_WARNING "Need to add type to trace.h\n");
                WARN_ON(1);
-       }
-
-       if (ftrace_find_event(event->type))
                goto out;
+       } else {
+               /* Is this event already used */
+               if (ftrace_find_event(event->type))
+                       goto out;
+       }
 
        if (event->trace == NULL)
                event->trace = trace_nop_print;
@@ -520,14 +692,25 @@ int register_ftrace_event(struct trace_event *event)
 
        key = event->type & (EVENT_HASHSIZE - 1);
 
-       hlist_add_head_rcu(&event->node, &event_hash[key]);
+       hlist_add_head(&event->node, &event_hash[key]);
 
        ret = event->type;
  out:
-       mutex_unlock(&trace_event_mutex);
+       up_write(&trace_event_mutex);
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(register_ftrace_event);
+
+/*
+ * Used by module code with the trace_event_mutex held for write.
+ */
+int __unregister_ftrace_event(struct trace_event *event)
+{
+       hlist_del(&event->node);
+       list_del(&event->list);
+       return 0;
+}
 
 /**
  * unregister_ftrace_event - remove a no longer used event
@@ -535,12 +718,13 @@ int register_ftrace_event(struct trace_event *event)
  */
 int unregister_ftrace_event(struct trace_event *event)
 {
-       mutex_lock(&trace_event_mutex);
-       hlist_del(&event->node);
-       mutex_unlock(&trace_event_mutex);
+       down_write(&trace_event_mutex);
+       __unregister_ftrace_event(event);
+       up_write(&trace_event_mutex);
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(unregister_ftrace_event);
 
 /*
  * Standard events
@@ -833,14 +1017,16 @@ static enum print_line_t trace_stack_print(struct trace_iterator *iter,
 
        trace_assign_type(field, iter->ent);
 
+       if (!trace_seq_puts(s, "<stack trace>\n"))
+               goto partial;
        for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
-               if (i) {
-                       if (!trace_seq_puts(s, " <= "))
-                               goto partial;
+               if (!field->caller[i] || (field->caller[i] == ULONG_MAX))
+                       break;
+               if (!trace_seq_puts(s, " => "))
+                       goto partial;
 
-                       if (!seq_print_ip_sym(s, field->caller[i], flags))
-                               goto partial;
-               }
+               if (!seq_print_ip_sym(s, field->caller[i], flags))
+                       goto partial;
                if (!trace_seq_puts(s, "\n"))
                        goto partial;
        }
@@ -868,10 +1054,10 @@ static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
 
        trace_assign_type(field, iter->ent);
 
-       if (!seq_print_userip_objs(field, s, flags))
+       if (!trace_seq_puts(s, "<user stack trace>\n"))
                goto partial;
 
-       if (!trace_seq_putc(s, '\n'))
+       if (!seq_print_userip_objs(field, s, flags))
                goto partial;
 
        return TRACE_TYPE_HANDLED;
index e0bde39c2dd9b00ab8ac5388aa0b5168fe5f37d2..d38bec4a9c3081e52bca0dec51e04e94827cba67 100644 (file)
@@ -1,41 +1,17 @@
 #ifndef __TRACE_EVENTS_H
 #define __TRACE_EVENTS_H
 
+#include <linux/trace_seq.h>
 #include "trace.h"
 
-typedef enum print_line_t (*trace_print_func)(struct trace_iterator *iter,
-                                             int flags);
-
-struct trace_event {
-       struct hlist_node       node;
-       int                     type;
-       trace_print_func        trace;
-       trace_print_func        raw;
-       trace_print_func        hex;
-       trace_print_func        binary;
-};
-
 extern enum print_line_t
 trace_print_bprintk_msg_only(struct trace_iterator *iter);
 extern enum print_line_t
 trace_print_printk_msg_only(struct trace_iterator *iter);
 
-extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
-       __attribute__ ((format (printf, 2, 3)));
-extern int
-trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary);
 extern int
 seq_print_ip_sym(struct trace_seq *s, unsigned long ip,
                unsigned long sym_flags);
-extern ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf,
-                                size_t cnt);
-extern int trace_seq_puts(struct trace_seq *s, const char *str);
-extern int trace_seq_putc(struct trace_seq *s, unsigned char c);
-extern int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len);
-extern int trace_seq_putmem_hex(struct trace_seq *s, const void *mem,
-                               size_t len);
-extern void *trace_seq_reserve(struct trace_seq *s, size_t len);
-extern int trace_seq_path(struct trace_seq *s, struct path *path);
 extern int seq_print_userip_objs(const struct userstack_entry *entry,
                                 struct trace_seq *s, unsigned long sym_flags);
 extern int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
@@ -44,13 +20,17 @@ extern int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
 extern int trace_print_context(struct trace_iterator *iter);
 extern int trace_print_lat_context(struct trace_iterator *iter);
 
+extern void trace_event_read_lock(void);
+extern void trace_event_read_unlock(void);
 extern struct trace_event *ftrace_find_event(int type);
-extern int register_ftrace_event(struct trace_event *event);
-extern int unregister_ftrace_event(struct trace_event *event);
 
 extern enum print_line_t trace_nop_print(struct trace_iterator *iter,
                                         int flags);
 
+/* used by module unregistering */
+extern int __unregister_ftrace_event(struct trace_event *event);
+extern struct rw_semaphore trace_event_mutex;
+
 #define MAX_MEMHEX_BYTES       8
 #define HEX_CHARS              (MAX_MEMHEX_BYTES*2 + 1)
 
index 118439709fb771f4fa2ad576454e0b64d1274144..8a30d9874cd430d507c3f9e997610430f1bcb894 100644 (file)
@@ -36,6 +36,7 @@ static void probe_power_start(struct power_trace *it, unsigned int type,
 
 static void probe_power_end(struct power_trace *it)
 {
+       struct ftrace_event_call *call = &event_power;
        struct ring_buffer_event *event;
        struct trace_power *entry;
        struct trace_array_cpu *data;
@@ -54,7 +55,8 @@ static void probe_power_end(struct power_trace *it)
                goto out;
        entry   = ring_buffer_event_data(event);
        entry->state_data = *it;
-       trace_buffer_unlock_commit(tr, event, 0, 0);
+       if (!filter_check_discard(call, entry, tr->buffer, event))
+               trace_buffer_unlock_commit(tr, event, 0, 0);
  out:
        preempt_enable();
 }
@@ -62,6 +64,7 @@ static void probe_power_end(struct power_trace *it)
 static void probe_power_mark(struct power_trace *it, unsigned int type,
                                unsigned int level)
 {
+       struct ftrace_event_call *call = &event_power;
        struct ring_buffer_event *event;
        struct trace_power *entry;
        struct trace_array_cpu *data;
@@ -84,7 +87,8 @@ static void probe_power_mark(struct power_trace *it, unsigned int type,
                goto out;
        entry   = ring_buffer_event_data(event);
        entry->state_data = *it;
-       trace_buffer_unlock_commit(tr, event, 0, 0);
+       if (!filter_check_discard(call, entry, tr->buffer, event))
+               trace_buffer_unlock_commit(tr, event, 0, 0);
  out:
        preempt_enable();
 }
index eb81556107fec71dc8ba53278df9264862df0f3b..9bece9687b62a8d2ab6b59199017ef0ad7898b98 100644 (file)
@@ -245,17 +245,13 @@ static const struct file_operations ftrace_formats_fops = {
 static __init int init_trace_printk_function_export(void)
 {
        struct dentry *d_tracer;
-       struct dentry *entry;
 
        d_tracer = tracing_init_dentry();
        if (!d_tracer)
                return 0;
 
-       entry = debugfs_create_file("printk_formats", 0444, d_tracer,
+       trace_create_file("printk_formats", 0444, d_tracer,
                                    NULL, &ftrace_formats_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs "
-                          "'printk_formats' entry\n");
 
        return 0;
 }
index 9117cea6f1ae78f17f2be7fc9894aa9b0abe2075..a98106dd979cfd7bd305cfab5a506fec61e95e46 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/kallsyms.h>
 #include <linux/uaccess.h>
 #include <linux/ftrace.h>
-#include <trace/sched.h>
+#include <trace/events/sched.h>
 
 #include "trace.h"
 
@@ -29,13 +29,13 @@ probe_sched_switch(struct rq *__rq, struct task_struct *prev,
        int cpu;
        int pc;
 
-       if (!sched_ref || sched_stopped)
+       if (unlikely(!sched_ref))
                return;
 
        tracing_record_cmdline(prev);
        tracing_record_cmdline(next);
 
-       if (!tracer_enabled)
+       if (!tracer_enabled || sched_stopped)
                return;
 
        pc = preempt_count();
@@ -56,15 +56,15 @@ probe_sched_wakeup(struct rq *__rq, struct task_struct *wakee, int success)
        unsigned long flags;
        int cpu, pc;
 
-       if (!likely(tracer_enabled))
+       if (unlikely(!sched_ref))
                return;
 
-       pc = preempt_count();
        tracing_record_cmdline(current);
 
-       if (sched_stopped)
+       if (!tracer_enabled || sched_stopped)
                return;
 
+       pc = preempt_count();
        local_irq_save(flags);
        cpu = raw_smp_processor_id();
        data = ctx_trace->data[cpu];
index 5bc00e8f153ebb8682589caa37b553b05800f6b0..eacb272251736276335a02d04a83b856ec550dfb 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/kallsyms.h>
 #include <linux/uaccess.h>
 #include <linux/ftrace.h>
-#include <trace/sched.h>
+#include <trace/events/sched.h>
 
 #include "trace.h"
 
@@ -138,9 +138,6 @@ probe_wakeup_sched_switch(struct rq *rq, struct task_struct *prev,
 
        pc = preempt_count();
 
-       /* The task we are waiting for is waking up */
-       data = wakeup_trace->data[wakeup_cpu];
-
        /* disable local data, not wakeup_cpu data */
        cpu = raw_smp_processor_id();
        disabled = atomic_inc_return(&wakeup_trace->data[cpu]->disabled);
@@ -154,6 +151,9 @@ probe_wakeup_sched_switch(struct rq *rq, struct task_struct *prev,
        if (unlikely(!tracer_enabled || next != wakeup_task))
                goto out_unlock;
 
+       /* The task we are waiting for is waking up */
+       data = wakeup_trace->data[wakeup_cpu];
+
        trace_function(wakeup_trace, CALLER_ADDR0, CALLER_ADDR1, flags, pc);
        tracing_sched_switch_trace(wakeup_trace, prev, next, flags, pc);
 
index 08f4eb2763d141bbae33c518a4de1e15d1c3614a..00dd6485bdd7e7abf390a6fcbe1c27d626a8531e 100644 (file)
@@ -16,6 +16,7 @@ static inline int trace_valid_entry(struct trace_entry *entry)
        case TRACE_BRANCH:
        case TRACE_GRAPH_ENT:
        case TRACE_GRAPH_RET:
+       case TRACE_HW_BRANCHES:
                return 1;
        }
        return 0;
@@ -188,6 +189,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
 #else
 # define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; })
 #endif /* CONFIG_DYNAMIC_FTRACE */
+
 /*
  * Simple verification test of ftrace function tracer.
  * Enable ftrace, sleep 1/10 second, and then read the trace
@@ -749,3 +751,59 @@ trace_selftest_startup_branch(struct tracer *trace, struct trace_array *tr)
        return ret;
 }
 #endif /* CONFIG_BRANCH_TRACER */
+
+#ifdef CONFIG_HW_BRANCH_TRACER
+int
+trace_selftest_startup_hw_branches(struct tracer *trace,
+                                  struct trace_array *tr)
+{
+       struct trace_iterator *iter;
+       struct tracer tracer;
+       unsigned long count;
+       int ret;
+
+       if (!trace->open) {
+               printk(KERN_CONT "missing open function...");
+               return -1;
+       }
+
+       ret = tracer_init(trace, tr);
+       if (ret) {
+               warn_failed_init_tracer(trace, ret);
+               return ret;
+       }
+
+       /*
+        * The hw-branch tracer needs to collect the trace from the various
+        * cpu trace buffers - before tracing is stopped.
+        */
+       iter = kzalloc(sizeof(*iter), GFP_KERNEL);
+       if (!iter)
+               return -ENOMEM;
+
+       memcpy(&tracer, trace, sizeof(tracer));
+
+       iter->trace = &tracer;
+       iter->tr = tr;
+       iter->pos = -1;
+       mutex_init(&iter->mutex);
+
+       trace->open(iter);
+
+       mutex_destroy(&iter->mutex);
+       kfree(iter);
+
+       tracing_stop();
+
+       ret = trace_test_buffer(tr, &count);
+       trace->reset(tr);
+       tracing_start();
+
+       if (!ret && !count) {
+               printk(KERN_CONT "no entries found..");
+               ret = -1;
+       }
+
+       return ret;
+}
+#endif /* CONFIG_HW_BRANCH_TRACER */
index c750f65f9661531273ee16553623b405268fc758..2d7aebd71dbd4e3489b8bf59fd29585b422be8e9 100644 (file)
@@ -265,7 +265,7 @@ static int t_show(struct seq_file *m, void *v)
                seq_printf(m, "        Depth    Size   Location"
                           "    (%d entries)\n"
                           "        -----    ----   --------\n",
-                          max_stack_trace.nr_entries);
+                          max_stack_trace.nr_entries - 1);
 
                if (!stack_tracer_enabled && !max_stack_size)
                        print_disabled(m);
@@ -352,19 +352,14 @@ __setup("stacktrace", enable_stacktrace);
 static __init int stack_trace_init(void)
 {
        struct dentry *d_tracer;
-       struct dentry *entry;
 
        d_tracer = tracing_init_dentry();
 
-       entry = debugfs_create_file("stack_max_size", 0644, d_tracer,
-                                   &max_stack_size, &stack_max_size_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'stack_max_size' entry\n");
+       trace_create_file("stack_max_size", 0644, d_tracer,
+                       &max_stack_size, &stack_max_size_fops);
 
-       entry = debugfs_create_file("stack_trace", 0444, d_tracer,
-                                   NULL, &stack_trace_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'stack_trace' entry\n");
+       trace_create_file("stack_trace", 0444, d_tracer,
+                       NULL, &stack_trace_fops);
 
        if (stack_tracer_enabled)
                register_ftrace_function(&trace_ops);
index acdebd771a93b9623e57b8ed922c988524254ba7..c00643733f4ccca7be15b22ef311ec03711edc48 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Infrastructure for statistic tracing (histogram output).
  *
- * Copyright (C) 2008 Frederic Weisbecker <fweisbec@gmail.com>
+ * Copyright (C) 2008-2009 Frederic Weisbecker <fweisbec@gmail.com>
  *
  * Based on the code from trace_branch.c which is
  * Copyright (C) 2008 Steven Rostedt <srostedt@redhat.com>
 
 
 #include <linux/list.h>
+#include <linux/rbtree.h>
 #include <linux/debugfs.h>
 #include "trace_stat.h"
 #include "trace.h"
 
 
-/* List of stat entries from a tracer */
-struct trace_stat_list {
-       struct list_head        list;
+/*
+ * List of stat red-black nodes from a tracer
+ * We use a such tree to sort quickly the stat
+ * entries from the tracer.
+ */
+struct stat_node {
+       struct rb_node          node;
        void                    *stat;
 };
 
 /* A stat session is the stats output in one file */
-struct tracer_stat_session {
+struct stat_session {
        struct list_head        session_list;
        struct tracer_stat      *ts;
-       struct list_head        stat_list;
+       struct rb_root          stat_root;
        struct mutex            stat_mutex;
        struct dentry           *file;
 };
@@ -37,18 +42,48 @@ static DEFINE_MUTEX(all_stat_sessions_mutex);
 /* The root directory for all stat files */
 static struct dentry           *stat_dir;
 
+/*
+ * Iterate through the rbtree using a post order traversal path
+ * to release the next node.
+ * It won't necessary release one at each iteration
+ * but it will at least advance closer to the next one
+ * to be released.
+ */
+static struct rb_node *release_next(struct rb_node *node)
+{
+       struct stat_node *snode;
+       struct rb_node *parent = rb_parent(node);
+
+       if (node->rb_left)
+               return node->rb_left;
+       else if (node->rb_right)
+               return node->rb_right;
+       else {
+               if (!parent)
+                       ;
+               else if (parent->rb_left == node)
+                       parent->rb_left = NULL;
+               else
+                       parent->rb_right = NULL;
+
+               snode = container_of(node, struct stat_node, node);
+               kfree(snode);
+
+               return parent;
+       }
+}
 
-static void reset_stat_session(struct tracer_stat_session *session)
+static void reset_stat_session(struct stat_session *session)
 {
-       struct trace_stat_list *node, *next;
+       struct rb_node *node = session->stat_root.rb_node;
 
-       list_for_each_entry_safe(node, next, &session->stat_list, list)
-               kfree(node);
+       while (node)
+               node = release_next(node);
 
-       INIT_LIST_HEAD(&session->stat_list);
+       session->stat_root = RB_ROOT;
 }
 
-static void destroy_session(struct tracer_stat_session *session)
+static void destroy_session(struct stat_session *session)
 {
        debugfs_remove(session->file);
        reset_stat_session(session);
@@ -56,25 +91,60 @@ static void destroy_session(struct tracer_stat_session *session)
        kfree(session);
 }
 
+typedef int (*cmp_stat_t)(void *, void *);
+
+static int insert_stat(struct rb_root *root, void *stat, cmp_stat_t cmp)
+{
+       struct rb_node **new = &(root->rb_node), *parent = NULL;
+       struct stat_node *data;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+       data->stat = stat;
+
+       /*
+        * Figure out where to put new node
+        * This is a descendent sorting
+        */
+       while (*new) {
+               struct stat_node *this;
+               int result;
+
+               this = container_of(*new, struct stat_node, node);
+               result = cmp(data->stat, this->stat);
+
+               parent = *new;
+               if (result >= 0)
+                       new = &((*new)->rb_left);
+               else
+                       new = &((*new)->rb_right);
+       }
+
+       rb_link_node(&data->node, parent, new);
+       rb_insert_color(&data->node, root);
+       return 0;
+}
+
 /*
  * For tracers that don't provide a stat_cmp callback.
- * This one will force an immediate insertion on tail of
- * the list.
+ * This one will force an insertion as right-most node
+ * in the rbtree.
  */
 static int dummy_cmp(void *p1, void *p2)
 {
-       return 1;
+       return -1;
 }
 
 /*
- * Initialize the stat list at each trace_stat file opening.
+ * Initialize the stat rbtree at each trace_stat file opening.
  * All of these copies and sorting are required on all opening
  * since the stats could have changed between two file sessions.
  */
-static int stat_seq_init(struct tracer_stat_session *session)
+static int stat_seq_init(struct stat_session *session)
 {
-       struct trace_stat_list *iter_entry, *new_entry;
        struct tracer_stat *ts = session->ts;
+       struct rb_root *root = &session->stat_root;
        void *stat;
        int ret = 0;
        int i;
@@ -85,29 +155,16 @@ static int stat_seq_init(struct tracer_stat_session *session)
        if (!ts->stat_cmp)
                ts->stat_cmp = dummy_cmp;
 
-       stat = ts->stat_start();
+       stat = ts->stat_start(ts);
        if (!stat)
                goto exit;
 
-       /*
-        * The first entry. Actually this is the second, but the first
-        * one (the stat_list head) is pointless.
-        */
-       new_entry = kmalloc(sizeof(struct trace_stat_list), GFP_KERNEL);
-       if (!new_entry) {
-               ret = -ENOMEM;
+       ret = insert_stat(root, stat, ts->stat_cmp);
+       if (ret)
                goto exit;
-       }
-
-       INIT_LIST_HEAD(&new_entry->list);
-
-       list_add(&new_entry->list, &session->stat_list);
-
-       new_entry->stat = stat;
 
        /*
-        * Iterate over the tracer stat entries and store them in a sorted
-        * list.
+        * Iterate over the tracer stat entries and store them in an rbtree.
         */
        for (i = 1; ; i++) {
                stat = ts->stat_next(stat, i);
@@ -116,36 +173,16 @@ static int stat_seq_init(struct tracer_stat_session *session)
                if (!stat)
                        break;
 
-               new_entry = kmalloc(sizeof(struct trace_stat_list), GFP_KERNEL);
-               if (!new_entry) {
-                       ret = -ENOMEM;
-                       goto exit_free_list;
-               }
-
-               INIT_LIST_HEAD(&new_entry->list);
-               new_entry->stat = stat;
-
-               list_for_each_entry_reverse(iter_entry, &session->stat_list,
-                               list) {
-
-                       /* Insertion with a descendent sorting */
-                       if (ts->stat_cmp(iter_entry->stat,
-                                       new_entry->stat) >= 0) {
-
-                               list_add(&new_entry->list, &iter_entry->list);
-                               break;
-                       }
-               }
-
-               /* The current larger value */
-               if (list_empty(&new_entry->list))
-                       list_add(&new_entry->list, &session->stat_list);
+               ret = insert_stat(root, stat, ts->stat_cmp);
+               if (ret)
+                       goto exit_free_rbtree;
        }
+
 exit:
        mutex_unlock(&session->stat_mutex);
        return ret;
 
-exit_free_list:
+exit_free_rbtree:
        reset_stat_session(session);
        mutex_unlock(&session->stat_mutex);
        return ret;
@@ -154,38 +191,51 @@ exit_free_list:
 
 static void *stat_seq_start(struct seq_file *s, loff_t *pos)
 {
-       struct tracer_stat_session *session = s->private;
+       struct stat_session *session = s->private;
+       struct rb_node *node;
+       int i;
 
-       /* Prevent from tracer switch or stat_list modification */
+       /* Prevent from tracer switch or rbtree modification */
        mutex_lock(&session->stat_mutex);
 
        /* If we are in the beginning of the file, print the headers */
-       if (!*pos && session->ts->stat_headers)
+       if (!*pos && session->ts->stat_headers) {
+               (*pos)++;
                return SEQ_START_TOKEN;
+       }
 
-       return seq_list_start(&session->stat_list, *pos);
+       node = rb_first(&session->stat_root);
+       for (i = 0; node && i < *pos; i++)
+               node = rb_next(node);
+
+       (*pos)++;
+
+       return node;
 }
 
 static void *stat_seq_next(struct seq_file *s, void *p, loff_t *pos)
 {
-       struct tracer_stat_session *session = s->private;
+       struct stat_session *session = s->private;
+       struct rb_node *node = p;
+
+       (*pos)++;
 
        if (p == SEQ_START_TOKEN)
-               return seq_list_start(&session->stat_list, *pos);
+               return rb_first(&session->stat_root);
 
-       return seq_list_next(p, &session->stat_list, pos);
+       return rb_next(node);
 }
 
 static void stat_seq_stop(struct seq_file *s, void *p)
 {
-       struct tracer_stat_session *session = s->private;
+       struct stat_session *session = s->private;
        mutex_unlock(&session->stat_mutex);
 }
 
 static int stat_seq_show(struct seq_file *s, void *v)
 {
-       struct tracer_stat_session *session = s->private;
-       struct trace_stat_list *l = list_entry(v, struct trace_stat_list, list);
+       struct stat_session *session = s->private;
+       struct stat_node *l = container_of(v, struct stat_node, node);
 
        if (v == SEQ_START_TOKEN)
                return session->ts->stat_headers(s);
@@ -205,7 +255,7 @@ static int tracing_stat_open(struct inode *inode, struct file *file)
 {
        int ret;
 
-       struct tracer_stat_session *session = inode->i_private;
+       struct stat_session *session = inode->i_private;
 
        ret = seq_open(file, &trace_stat_seq_ops);
        if (!ret) {
@@ -218,11 +268,11 @@ static int tracing_stat_open(struct inode *inode, struct file *file)
 }
 
 /*
- * Avoid consuming memory with our now useless list.
+ * Avoid consuming memory with our now useless rbtree.
  */
 static int tracing_stat_release(struct inode *i, struct file *f)
 {
-       struct tracer_stat_session *session = i->i_private;
+       struct stat_session *session = i->i_private;
 
        mutex_lock(&session->stat_mutex);
        reset_stat_session(session);
@@ -251,7 +301,7 @@ static int tracing_stat_init(void)
        return 0;
 }
 
-static int init_stat_file(struct tracer_stat_session *session)
+static int init_stat_file(struct stat_session *session)
 {
        if (!stat_dir && tracing_stat_init())
                return -ENODEV;
@@ -266,7 +316,7 @@ static int init_stat_file(struct tracer_stat_session *session)
 
 int register_stat_tracer(struct tracer_stat *trace)
 {
-       struct tracer_stat_session *session, *node, *tmp;
+       struct stat_session *session, *node;
        int ret;
 
        if (!trace)
@@ -277,7 +327,7 @@ int register_stat_tracer(struct tracer_stat *trace)
 
        /* Already registered? */
        mutex_lock(&all_stat_sessions_mutex);
-       list_for_each_entry_safe(node, tmp, &all_stat_sessions, session_list) {
+       list_for_each_entry(node, &all_stat_sessions, session_list) {
                if (node->ts == trace) {
                        mutex_unlock(&all_stat_sessions_mutex);
                        return -EINVAL;
@@ -286,15 +336,13 @@ int register_stat_tracer(struct tracer_stat *trace)
        mutex_unlock(&all_stat_sessions_mutex);
 
        /* Init the session */
-       session = kmalloc(sizeof(struct tracer_stat_session), GFP_KERNEL);
+       session = kzalloc(sizeof(*session), GFP_KERNEL);
        if (!session)
                return -ENOMEM;
 
        session->ts = trace;
        INIT_LIST_HEAD(&session->session_list);
-       INIT_LIST_HEAD(&session->stat_list);
        mutex_init(&session->stat_mutex);
-       session->file = NULL;
 
        ret = init_stat_file(session);
        if (ret) {
@@ -312,7 +360,7 @@ int register_stat_tracer(struct tracer_stat *trace)
 
 void unregister_stat_tracer(struct tracer_stat *trace)
 {
-       struct tracer_stat_session *node, *tmp;
+       struct stat_session *node, *tmp;
 
        mutex_lock(&all_stat_sessions_mutex);
        list_for_each_entry_safe(node, tmp, &all_stat_sessions, session_list) {
index 202274cf7f3d06d1145437ab8cd27d43eaf90e04..f3546a2cd826bc6ae0ecb85c3c631bd411884aab 100644 (file)
@@ -12,7 +12,7 @@ struct tracer_stat {
        /* The name of your stat file */
        const char              *name;
        /* Iteration over statistic entries */
-       void                    *(*stat_start)(void);
+       void                    *(*stat_start)(struct tracer_stat *trace);
        void                    *(*stat_next)(void *prev, int idx);
        /* Compare two entries for stats sorting */
        int                     (*stat_cmp)(void *p1, void *p2);
index 91fd19c2149f5c57e37e808286bc4a3f1929510e..e04b76cc238a69816cd96b57146afbc97cc36da1 100644 (file)
@@ -321,11 +321,7 @@ static const struct file_operations sysprof_sample_fops = {
 
 void init_tracer_sysprof_debugfs(struct dentry *d_tracer)
 {
-       struct dentry *entry;
 
-       entry = debugfs_create_file("sysprof_sample_period", 0644,
+       trace_create_file("sysprof_sample_period", 0644,
                        d_tracer, NULL, &sysprof_sample_fops);
-       if (entry)
-               return;
-       pr_warning("Could not create debugfs 'sysprof_sample_period' entry\n");
 }
index 797201e4a1376af5987bbce519398b14de3aeada..97fcea4acce156228e29490345373938d92277d8 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 
-#include <trace/workqueue.h>
+#include <trace/events/workqueue.h>
 #include <linux/list.h>
 #include <linux/percpu.h>
 #include "trace_stat.h"
@@ -16,8 +16,6 @@
 /* A cpu workqueue thread */
 struct cpu_workqueue_stats {
        struct list_head            list;
-/* Useful to know if we print the cpu headers */
-       bool                        first_entry;
        int                         cpu;
        pid_t                       pid;
 /* Can be inserted from interrupt or user context, need to be atomic */
@@ -47,12 +45,11 @@ probe_workqueue_insertion(struct task_struct *wq_thread,
                          struct work_struct *work)
 {
        int cpu = cpumask_first(&wq_thread->cpus_allowed);
-       struct cpu_workqueue_stats *node, *next;
+       struct cpu_workqueue_stats *node;
        unsigned long flags;
 
        spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
-       list_for_each_entry_safe(node, next, &workqueue_cpu_stat(cpu)->list,
-                                                       list) {
+       list_for_each_entry(node, &workqueue_cpu_stat(cpu)->list, list) {
                if (node->pid == wq_thread->pid) {
                        atomic_inc(&node->inserted);
                        goto found;
@@ -69,12 +66,11 @@ probe_workqueue_execution(struct task_struct *wq_thread,
                          struct work_struct *work)
 {
        int cpu = cpumask_first(&wq_thread->cpus_allowed);
-       struct cpu_workqueue_stats *node, *next;
+       struct cpu_workqueue_stats *node;
        unsigned long flags;
 
        spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
-       list_for_each_entry_safe(node, next, &workqueue_cpu_stat(cpu)->list,
-                                                       list) {
+       list_for_each_entry(node, &workqueue_cpu_stat(cpu)->list, list) {
                if (node->pid == wq_thread->pid) {
                        node->executed++;
                        goto found;
@@ -105,8 +101,6 @@ static void probe_workqueue_creation(struct task_struct *wq_thread, int cpu)
        cws->pid = wq_thread->pid;
 
        spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
-       if (list_empty(&workqueue_cpu_stat(cpu)->list))
-               cws->first_entry = true;
        list_add_tail(&cws->list, &workqueue_cpu_stat(cpu)->list);
        spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
 }
@@ -152,7 +146,7 @@ static struct cpu_workqueue_stats *workqueue_stat_start_cpu(int cpu)
        return ret;
 }
 
-static void *workqueue_stat_start(void)
+static void *workqueue_stat_start(struct tracer_stat *trace)
 {
        int cpu;
        void *ret = NULL;
@@ -191,16 +185,9 @@ static void *workqueue_stat_next(void *prev, int idx)
 static int workqueue_stat_show(struct seq_file *s, void *p)
 {
        struct cpu_workqueue_stats *cws = p;
-       unsigned long flags;
-       int cpu = cws->cpu;
        struct pid *pid;
        struct task_struct *tsk;
 
-       spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
-       if (&cws->list == workqueue_cpu_stat(cpu)->list.next)
-               seq_printf(s, "\n");
-       spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
-
        pid = find_get_pid(cws->pid);
        if (pid) {
                tsk = get_pid_task(pid, PIDTYPE_PID);
index 42a2dbc181c89ca708360d84ee53a5ca21640b44..ea7c3b4275cf362f75cee939aa7861f7673b95cc 100644 (file)
@@ -154,7 +154,7 @@ void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait,
        if (!list_empty(&wait->task_list))
                list_del_init(&wait->task_list);
        else if (waitqueue_active(q))
-               __wake_up_common(q, mode, 1, 0, key);
+               __wake_up_locked_key(q, mode, key);
        spin_unlock_irqrestore(&q->lock, flags);
 }
 EXPORT_SYMBOL(abort_exclusive_wait);
index f71fb2a089503534eec8d8790f82d9702a3545cc..0668795d8818477683d184edff057f6fe19144ad 100644 (file)
@@ -33,7 +33,8 @@
 #include <linux/kallsyms.h>
 #include <linux/debug_locks.h>
 #include <linux/lockdep.h>
-#include <trace/workqueue.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/workqueue.h>
 
 /*
  * The per-CPU workqueue (if single thread, we always use the first
@@ -124,8 +125,6 @@ struct cpu_workqueue_struct *get_wq_data(struct work_struct *work)
        return (void *) (atomic_long_read(&work->data) & WORK_STRUCT_WQ_DATA_MASK);
 }
 
-DEFINE_TRACE(workqueue_insertion);
-
 static void insert_work(struct cpu_workqueue_struct *cwq,
                        struct work_struct *work, struct list_head *head)
 {
@@ -262,8 +261,6 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
 }
 EXPORT_SYMBOL_GPL(queue_delayed_work_on);
 
-DEFINE_TRACE(workqueue_execution);
-
 static void run_workqueue(struct cpu_workqueue_struct *cwq)
 {
        spin_lock_irq(&cwq->lock);
@@ -753,8 +750,6 @@ init_cpu_workqueue(struct workqueue_struct *wq, int cpu)
        return cwq;
 }
 
-DEFINE_TRACE(workqueue_creation);
-
 static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
 {
        struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
@@ -860,8 +855,6 @@ struct workqueue_struct *__create_workqueue_key(const char *name,
 }
 EXPORT_SYMBOL_GPL(__create_workqueue_key);
 
-DEFINE_TRACE(workqueue_destruction);
-
 static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq)
 {
        /*
index 8ade0a7a91e09ae11e4921338d5363ee74803d05..9960be04cbbe608cad81733096dd49d73928dbba 100644 (file)
@@ -10,6 +10,9 @@ menu "Library routines"
 config BITREVERSE
        tristate
 
+config RATIONAL
+       boolean
+
 config GENERIC_FIND_FIRST_BIT
        bool
 
index 33a40e40e3ee44807b0347add1a81aaf0390d7a7..1f6edefebffe3f7fd94d0348b97d0dd6d80a9dc1 100644 (file)
@@ -50,6 +50,7 @@ ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
 endif
 
 obj-$(CONFIG_BITREVERSE) += bitrev.o
+obj-$(CONFIG_RATIONAL) += rational.o
 obj-$(CONFIG_CRC_CCITT)        += crc-ccitt.o
 obj-$(CONFIG_CRC16)    += crc16.o
 obj-$(CONFIG_CRC_T10DIF)+= crc-t10dif.o
index 69da09a085a1943ea6a70f4871fd2df1683110fb..ad65fc0317d93b6c1dd20171e625e7e619631d21 100644 (file)
 #include <linux/dma-debug.h>
 #include <linux/spinlock.h>
 #include <linux/debugfs.h>
+#include <linux/uaccess.h>
 #include <linux/device.h>
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <linux/ctype.h>
 #include <linux/list.h>
 #include <linux/slab.h>
 
@@ -85,6 +87,7 @@ static u32 show_num_errors = 1;
 
 static u32 num_free_entries;
 static u32 min_free_entries;
+static u32 nr_total_entries;
 
 /* number of preallocated entries requested by kernel cmdline */
 static u32 req_entries;
@@ -97,6 +100,16 @@ static struct dentry *show_all_errors_dent  __read_mostly;
 static struct dentry *show_num_errors_dent  __read_mostly;
 static struct dentry *num_free_entries_dent __read_mostly;
 static struct dentry *min_free_entries_dent __read_mostly;
+static struct dentry *filter_dent           __read_mostly;
+
+/* per-driver filter related state */
+
+#define NAME_MAX_LEN   64
+
+static char                  current_driver_name[NAME_MAX_LEN] __read_mostly;
+static struct device_driver *current_driver                    __read_mostly;
+
+static DEFINE_RWLOCK(driver_name_lock);
 
 static const char *type2name[4] = { "single", "page",
                                    "scather-gather", "coherent" };
@@ -104,6 +117,11 @@ static const char *type2name[4] = { "single", "page",
 static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE",
                                   "DMA_FROM_DEVICE", "DMA_NONE" };
 
+/* little merge helper - remove it after the merge window */
+#ifndef BUS_NOTIFY_UNBOUND_DRIVER
+#define BUS_NOTIFY_UNBOUND_DRIVER 0x0005
+#endif
+
 /*
  * The access to some variables in this macro is racy. We can't use atomic_t
  * here because all these variables are exported to debugfs. Some of them even
@@ -121,15 +139,54 @@ static inline void dump_entry_trace(struct dma_debug_entry *entry)
 {
 #ifdef CONFIG_STACKTRACE
        if (entry) {
-               printk(KERN_WARNING "Mapped at:\n");
+               pr_warning("Mapped at:\n");
                print_stack_trace(&entry->stacktrace, 0);
        }
 #endif
 }
 
+static bool driver_filter(struct device *dev)
+{
+       struct device_driver *drv;
+       unsigned long flags;
+       bool ret;
+
+       /* driver filter off */
+       if (likely(!current_driver_name[0]))
+               return true;
+
+       /* driver filter on and initialized */
+       if (current_driver && dev->driver == current_driver)
+               return true;
+
+       if (current_driver || !current_driver_name[0])
+               return false;
+
+       /* driver filter on but not yet initialized */
+       drv = get_driver(dev->driver);
+       if (!drv)
+               return false;
+
+       /* lock to protect against change of current_driver_name */
+       read_lock_irqsave(&driver_name_lock, flags);
+
+       ret = false;
+       if (drv->name &&
+           strncmp(current_driver_name, drv->name, NAME_MAX_LEN - 1) == 0) {
+               current_driver = drv;
+               ret = true;
+       }
+
+       read_unlock_irqrestore(&driver_name_lock, flags);
+       put_driver(drv);
+
+       return ret;
+}
+
 #define err_printk(dev, entry, format, arg...) do {            \
                error_count += 1;                               \
-               if (show_all_errors || show_num_errors > 0) {   \
+               if (driver_filter(dev) &&                       \
+                   (show_all_errors || show_num_errors > 0)) { \
                        WARN(1, "%s %s: " format,               \
                             dev_driver_string(dev),            \
                             dev_name(dev) , ## arg);           \
@@ -185,15 +242,50 @@ static void put_hash_bucket(struct hash_bucket *bucket,
 static struct dma_debug_entry *hash_bucket_find(struct hash_bucket *bucket,
                                                struct dma_debug_entry *ref)
 {
-       struct dma_debug_entry *entry;
+       struct dma_debug_entry *entry, *ret = NULL;
+       int matches = 0, match_lvl, last_lvl = 0;
 
        list_for_each_entry(entry, &bucket->list, list) {
-               if ((entry->dev_addr == ref->dev_addr) &&
-                   (entry->dev == ref->dev))
+               if ((entry->dev_addr != ref->dev_addr) ||
+                   (entry->dev != ref->dev))
+                       continue;
+
+               /*
+                * Some drivers map the same physical address multiple
+                * times. Without a hardware IOMMU this results in the
+                * same device addresses being put into the dma-debug
+                * hash multiple times too. This can result in false
+                * positives being reported. Therfore we implement a
+                * best-fit algorithm here which returns the entry from
+                * the hash which fits best to the reference value
+                * instead of the first-fit.
+                */
+               matches += 1;
+               match_lvl = 0;
+               entry->size      == ref->size      ? ++match_lvl : match_lvl;
+               entry->type      == ref->type      ? ++match_lvl : match_lvl;
+               entry->direction == ref->direction ? ++match_lvl : match_lvl;
+
+               if (match_lvl == 3) {
+                       /* perfect-fit - return the result */
                        return entry;
+               } else if (match_lvl > last_lvl) {
+                       /*
+                        * We found an entry that fits better then the
+                        * previous one
+                        */
+                       last_lvl = match_lvl;
+                       ret      = entry;
+               }
        }
 
-       return NULL;
+       /*
+        * If we have multiple matches but no perfect-fit, just return
+        * NULL.
+        */
+       ret = (matches == 1) ? ret : NULL;
+
+       return ret;
 }
 
 /*
@@ -257,6 +349,21 @@ static void add_dma_entry(struct dma_debug_entry *entry)
        put_hash_bucket(bucket, &flags);
 }
 
+static struct dma_debug_entry *__dma_entry_alloc(void)
+{
+       struct dma_debug_entry *entry;
+
+       entry = list_entry(free_entries.next, struct dma_debug_entry, list);
+       list_del(&entry->list);
+       memset(entry, 0, sizeof(*entry));
+
+       num_free_entries -= 1;
+       if (num_free_entries < min_free_entries)
+               min_free_entries = num_free_entries;
+
+       return entry;
+}
+
 /* struct dma_entry allocator
  *
  * The next two functions implement the allocator for
@@ -270,15 +377,12 @@ static struct dma_debug_entry *dma_entry_alloc(void)
        spin_lock_irqsave(&free_entries_lock, flags);
 
        if (list_empty(&free_entries)) {
-               printk(KERN_ERR "DMA-API: debugging out of memory "
-                               "- disabling\n");
+               pr_err("DMA-API: debugging out of memory - disabling\n");
                global_disable = true;
                goto out;
        }
 
-       entry = list_entry(free_entries.next, struct dma_debug_entry, list);
-       list_del(&entry->list);
-       memset(entry, 0, sizeof(*entry));
+       entry = __dma_entry_alloc();
 
 #ifdef CONFIG_STACKTRACE
        entry->stacktrace.max_entries = DMA_DEBUG_STACKTRACE_ENTRIES;
@@ -286,9 +390,6 @@ static struct dma_debug_entry *dma_entry_alloc(void)
        entry->stacktrace.skip = 2;
        save_stack_trace(&entry->stacktrace);
 #endif
-       num_free_entries -= 1;
-       if (num_free_entries < min_free_entries)
-               min_free_entries = num_free_entries;
 
 out:
        spin_unlock_irqrestore(&free_entries_lock, flags);
@@ -310,6 +411,53 @@ static void dma_entry_free(struct dma_debug_entry *entry)
        spin_unlock_irqrestore(&free_entries_lock, flags);
 }
 
+int dma_debug_resize_entries(u32 num_entries)
+{
+       int i, delta, ret = 0;
+       unsigned long flags;
+       struct dma_debug_entry *entry;
+       LIST_HEAD(tmp);
+
+       spin_lock_irqsave(&free_entries_lock, flags);
+
+       if (nr_total_entries < num_entries) {
+               delta = num_entries - nr_total_entries;
+
+               spin_unlock_irqrestore(&free_entries_lock, flags);
+
+               for (i = 0; i < delta; i++) {
+                       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+                       if (!entry)
+                               break;
+
+                       list_add_tail(&entry->list, &tmp);
+               }
+
+               spin_lock_irqsave(&free_entries_lock, flags);
+
+               list_splice(&tmp, &free_entries);
+               nr_total_entries += i;
+               num_free_entries += i;
+       } else {
+               delta = nr_total_entries - num_entries;
+
+               for (i = 0; i < delta && !list_empty(&free_entries); i++) {
+                       entry = __dma_entry_alloc();
+                       kfree(entry);
+               }
+
+               nr_total_entries -= i;
+       }
+
+       if (nr_total_entries != num_entries)
+               ret = 1;
+
+       spin_unlock_irqrestore(&free_entries_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(dma_debug_resize_entries);
+
 /*
  * DMA-API debugging init code
  *
@@ -334,8 +482,7 @@ static int prealloc_memory(u32 num_entries)
        num_free_entries = num_entries;
        min_free_entries = num_entries;
 
-       printk(KERN_INFO "DMA-API: preallocated %d debug entries\n",
-                       num_entries);
+       pr_info("DMA-API: preallocated %d debug entries\n", num_entries);
 
        return 0;
 
@@ -349,11 +496,102 @@ out_err:
        return -ENOMEM;
 }
 
+static ssize_t filter_read(struct file *file, char __user *user_buf,
+                          size_t count, loff_t *ppos)
+{
+       char buf[NAME_MAX_LEN + 1];
+       unsigned long flags;
+       int len;
+
+       if (!current_driver_name[0])
+               return 0;
+
+       /*
+        * We can't copy to userspace directly because current_driver_name can
+        * only be read under the driver_name_lock with irqs disabled. So
+        * create a temporary copy first.
+        */
+       read_lock_irqsave(&driver_name_lock, flags);
+       len = scnprintf(buf, NAME_MAX_LEN + 1, "%s\n", current_driver_name);
+       read_unlock_irqrestore(&driver_name_lock, flags);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t filter_write(struct file *file, const char __user *userbuf,
+                           size_t count, loff_t *ppos)
+{
+       char buf[NAME_MAX_LEN];
+       unsigned long flags;
+       size_t len;
+       int i;
+
+       /*
+        * We can't copy from userspace directly. Access to
+        * current_driver_name is protected with a write_lock with irqs
+        * disabled. Since copy_from_user can fault and may sleep we
+        * need to copy to temporary buffer first
+        */
+       len = min(count, (size_t)(NAME_MAX_LEN - 1));
+       if (copy_from_user(buf, userbuf, len))
+               return -EFAULT;
+
+       buf[len] = 0;
+
+       write_lock_irqsave(&driver_name_lock, flags);
+
+       /*
+        * Now handle the string we got from userspace very carefully.
+        * The rules are:
+        *         - only use the first token we got
+        *         - token delimiter is everything looking like a space
+        *           character (' ', '\n', '\t' ...)
+        *
+        */
+       if (!isalnum(buf[0])) {
+               /*
+                * If the first character userspace gave us is not
+                * alphanumerical then assume the filter should be
+                * switched off.
+                */
+               if (current_driver_name[0])
+                       pr_info("DMA-API: switching off dma-debug driver filter\n");
+               current_driver_name[0] = 0;
+               current_driver = NULL;
+               goto out_unlock;
+       }
+
+       /*
+        * Now parse out the first token and use it as the name for the
+        * driver to filter for.
+        */
+       for (i = 0; i < NAME_MAX_LEN; ++i) {
+               current_driver_name[i] = buf[i];
+               if (isspace(buf[i]) || buf[i] == ' ' || buf[i] == 0)
+                       break;
+       }
+       current_driver_name[i] = 0;
+       current_driver = NULL;
+
+       pr_info("DMA-API: enable driver filter for driver [%s]\n",
+               current_driver_name);
+
+out_unlock:
+       write_unlock_irqrestore(&driver_name_lock, flags);
+
+       return count;
+}
+
+const struct file_operations filter_fops = {
+       .read  = filter_read,
+       .write = filter_write,
+};
+
 static int dma_debug_fs_init(void)
 {
        dma_debug_dent = debugfs_create_dir("dma-api", NULL);
        if (!dma_debug_dent) {
-               printk(KERN_ERR "DMA-API: can not create debugfs directory\n");
+               pr_err("DMA-API: can not create debugfs directory\n");
                return -ENOMEM;
        }
 
@@ -392,6 +630,11 @@ static int dma_debug_fs_init(void)
        if (!min_free_entries_dent)
                goto out_err;
 
+       filter_dent = debugfs_create_file("driver_filter", 0644,
+                                         dma_debug_dent, NULL, &filter_fops);
+       if (!filter_dent)
+               goto out_err;
+
        return 0;
 
 out_err:
@@ -400,9 +643,64 @@ out_err:
        return -ENOMEM;
 }
 
+static int device_dma_allocations(struct device *dev)
+{
+       struct dma_debug_entry *entry;
+       unsigned long flags;
+       int count = 0, i;
+
+       local_irq_save(flags);
+
+       for (i = 0; i < HASH_SIZE; ++i) {
+               spin_lock(&dma_entry_hash[i].lock);
+               list_for_each_entry(entry, &dma_entry_hash[i].list, list) {
+                       if (entry->dev == dev)
+                               count += 1;
+               }
+               spin_unlock(&dma_entry_hash[i].lock);
+       }
+
+       local_irq_restore(flags);
+
+       return count;
+}
+
+static int dma_debug_device_change(struct notifier_block *nb,
+                                   unsigned long action, void *data)
+{
+       struct device *dev = data;
+       int count;
+
+
+       switch (action) {
+       case BUS_NOTIFY_UNBOUND_DRIVER:
+               count = device_dma_allocations(dev);
+               if (count == 0)
+                       break;
+               err_printk(dev, NULL, "DMA-API: device driver has pending "
+                               "DMA allocations while released from device "
+                               "[count=%d]\n", count);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 void dma_debug_add_bus(struct bus_type *bus)
 {
-       /* FIXME: register notifier */
+       struct notifier_block *nb;
+
+       nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL);
+       if (nb == NULL) {
+               pr_err("dma_debug_add_bus: out of memory\n");
+               return;
+       }
+
+       nb->notifier_call = dma_debug_device_change;
+
+       bus_register_notifier(bus, nb);
 }
 
 /*
@@ -421,8 +719,7 @@ void dma_debug_init(u32 num_entries)
        }
 
        if (dma_debug_fs_init() != 0) {
-               printk(KERN_ERR "DMA-API: error creating debugfs entries "
-                               "- disabling\n");
+               pr_err("DMA-API: error creating debugfs entries - disabling\n");
                global_disable = true;
 
                return;
@@ -432,14 +729,15 @@ void dma_debug_init(u32 num_entries)
                num_entries = req_entries;
 
        if (prealloc_memory(num_entries) != 0) {
-               printk(KERN_ERR "DMA-API: debugging out of memory error "
-                               "- disabled\n");
+               pr_err("DMA-API: debugging out of memory error - disabled\n");
                global_disable = true;
 
                return;
        }
 
-       printk(KERN_INFO "DMA-API: debugging enabled by kernel config\n");
+       nr_total_entries = num_free_entries;
+
+       pr_info("DMA-API: debugging enabled by kernel config\n");
 }
 
 static __init int dma_debug_cmdline(char *str)
@@ -448,8 +746,7 @@ static __init int dma_debug_cmdline(char *str)
                return -EINVAL;
 
        if (strncmp(str, "off", 3) == 0) {
-               printk(KERN_INFO "DMA-API: debugging disabled on kernel "
-                                "command line\n");
+               pr_info("DMA-API: debugging disabled on kernel command line\n");
                global_disable = true;
        }
 
@@ -723,15 +1020,15 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
                entry->type           = dma_debug_sg;
                entry->dev            = dev;
                entry->paddr          = sg_phys(s);
-               entry->size           = s->length;
-               entry->dev_addr       = s->dma_address;
+               entry->size           = sg_dma_len(s);
+               entry->dev_addr       = sg_dma_address(s);
                entry->direction      = direction;
                entry->sg_call_ents   = nents;
                entry->sg_mapped_ents = mapped_ents;
 
                if (!PageHighMem(sg_page(s))) {
                        check_for_stack(dev, sg_virt(s));
-                       check_for_illegal_area(dev, sg_virt(s), s->length);
+                       check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s));
                }
 
                add_dma_entry(entry);
@@ -739,13 +1036,33 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
 }
 EXPORT_SYMBOL(debug_dma_map_sg);
 
+static int get_nr_mapped_entries(struct device *dev, struct scatterlist *s)
+{
+       struct dma_debug_entry *entry, ref;
+       struct hash_bucket *bucket;
+       unsigned long flags;
+       int mapped_ents;
+
+       ref.dev      = dev;
+       ref.dev_addr = sg_dma_address(s);
+       ref.size     = sg_dma_len(s),
+
+       bucket       = get_hash_bucket(&ref, &flags);
+       entry        = hash_bucket_find(bucket, &ref);
+       mapped_ents  = 0;
+
+       if (entry)
+               mapped_ents = entry->sg_mapped_ents;
+       put_hash_bucket(bucket, &flags);
+
+       return mapped_ents;
+}
+
 void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
                        int nelems, int dir)
 {
-       struct dma_debug_entry *entry;
        struct scatterlist *s;
        int mapped_ents = 0, i;
-       unsigned long flags;
 
        if (unlikely(global_disable))
                return;
@@ -756,8 +1073,8 @@ void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
                        .type           = dma_debug_sg,
                        .dev            = dev,
                        .paddr          = sg_phys(s),
-                       .dev_addr       = s->dma_address,
-                       .size           = s->length,
+                       .dev_addr       = sg_dma_address(s),
+                       .size           = sg_dma_len(s),
                        .direction      = dir,
                        .sg_call_ents   = 0,
                };
@@ -765,14 +1082,9 @@ void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
                if (mapped_ents && i >= mapped_ents)
                        break;
 
-               if (mapped_ents == 0) {
-                       struct hash_bucket *bucket;
+               if (!i) {
                        ref.sg_call_ents = nelems;
-                       bucket = get_hash_bucket(&ref, &flags);
-                       entry = hash_bucket_find(bucket, &ref);
-                       if (entry)
-                               mapped_ents = entry->sg_mapped_ents;
-                       put_hash_bucket(bucket, &flags);
+                       mapped_ents = get_nr_mapped_entries(dev, s);
                }
 
                check_unmap(&ref);
@@ -874,14 +1186,20 @@ void debug_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
                               int nelems, int direction)
 {
        struct scatterlist *s;
-       int i;
+       int mapped_ents = 0, i;
 
        if (unlikely(global_disable))
                return;
 
        for_each_sg(sg, s, nelems, i) {
-               check_sync(dev, s->dma_address, s->dma_length, 0,
-                               direction, true);
+               if (!i)
+                       mapped_ents = get_nr_mapped_entries(dev, s);
+
+               if (i >= mapped_ents)
+                       break;
+
+               check_sync(dev, sg_dma_address(s), sg_dma_len(s), 0,
+                          direction, true);
        }
 }
 EXPORT_SYMBOL(debug_dma_sync_sg_for_cpu);
@@ -890,15 +1208,39 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
                                  int nelems, int direction)
 {
        struct scatterlist *s;
-       int i;
+       int mapped_ents = 0, i;
 
        if (unlikely(global_disable))
                return;
 
        for_each_sg(sg, s, nelems, i) {
-               check_sync(dev, s->dma_address, s->dma_length, 0,
-                               direction, false);
+               if (!i)
+                       mapped_ents = get_nr_mapped_entries(dev, s);
+
+               if (i >= mapped_ents)
+                       break;
+
+               check_sync(dev, sg_dma_address(s), sg_dma_len(s), 0,
+                          direction, false);
        }
 }
 EXPORT_SYMBOL(debug_dma_sync_sg_for_device);
 
+static int __init dma_debug_driver_setup(char *str)
+{
+       int i;
+
+       for (i = 0; i < NAME_MAX_LEN - 1; ++i, ++str) {
+               current_driver_name[i] = *str;
+               if (*str == 0)
+                       break;
+       }
+
+       if (current_driver_name[0])
+               pr_info("DMA-API: enable driver filter for driver [%s]\n",
+                       current_driver_name);
+
+
+       return 1;
+}
+__setup("dma_debug_driver=", dma_debug_driver_setup);
diff --git a/lib/rational.c b/lib/rational.c
new file mode 100644 (file)
index 0000000..b3c099b
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * rational fractions
+ *
+ * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <os@emlix.com>
+ *
+ * helper functions when coping with rational numbers
+ */
+
+#include <linux/rational.h>
+
+/*
+ * calculate best rational approximation for a given fraction
+ * taking into account restricted register size, e.g. to find
+ * appropriate values for a pll with 5 bit denominator and
+ * 8 bit numerator register fields, trying to set up with a
+ * frequency ratio of 3.1415, one would say:
+ *
+ * rational_best_approximation(31415, 10000,
+ *             (1 << 8) - 1, (1 << 5) - 1, &n, &d);
+ *
+ * you may look at given_numerator as a fixed point number,
+ * with the fractional part size described in given_denominator.
+ *
+ * for theoretical background, see:
+ * http://en.wikipedia.org/wiki/Continued_fraction
+ */
+
+void rational_best_approximation(
+       unsigned long given_numerator, unsigned long given_denominator,
+       unsigned long max_numerator, unsigned long max_denominator,
+       unsigned long *best_numerator, unsigned long *best_denominator)
+{
+       unsigned long n, d, n0, d0, n1, d1;
+       n = given_numerator;
+       d = given_denominator;
+       n0 = d1 = 0;
+       n1 = d0 = 1;
+       for (;;) {
+               unsigned long t, a;
+               if ((n1 > max_numerator) || (d1 > max_denominator)) {
+                       n1 = n0;
+                       d1 = d0;
+                       break;
+               }
+               if (d == 0)
+                       break;
+               t = d;
+               a = n / d;
+               d = n % d;
+               n = t;
+               t = n0 + a * n1;
+               n0 = n1;
+               n1 = t;
+               t = d0 + a * d1;
+               d0 = d1;
+               d1 = t;
+       }
+       *best_numerator = n1;
+       *best_denominator = d1;
+}
+
+EXPORT_SYMBOL(rational_best_approximation);
index 2b0b5a7d2ced165b1e2b83e2df888c237349f23f..bffe6d7ef9d9a01a52db11e12e54207bc9b41a0c 100644 (file)
@@ -60,8 +60,8 @@ enum dma_sync_target {
 int swiotlb_force;
 
 /*
- * Used to do a quick range check in swiotlb_unmap_single and
- * swiotlb_sync_single_*, to see if the memory was in fact allocated by this
+ * Used to do a quick range check in unmap_single and
+ * sync_single_*, to see if the memory was in fact allocated by this
  * API.
  */
 static char *io_tlb_start, *io_tlb_end;
@@ -129,7 +129,7 @@ dma_addr_t __weak swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr)
        return paddr;
 }
 
-phys_addr_t __weak swiotlb_bus_to_phys(dma_addr_t baddr)
+phys_addr_t __weak swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr)
 {
        return baddr;
 }
@@ -140,9 +140,15 @@ static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,
        return swiotlb_phys_to_bus(hwdev, virt_to_phys(address));
 }
 
-static void *swiotlb_bus_to_virt(dma_addr_t address)
+void * __weak swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
 {
-       return phys_to_virt(swiotlb_bus_to_phys(address));
+       return phys_to_virt(swiotlb_bus_to_phys(hwdev, address));
+}
+
+int __weak swiotlb_arch_address_needs_mapping(struct device *hwdev,
+                                              dma_addr_t addr, size_t size)
+{
+       return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size);
 }
 
 int __weak swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size)
@@ -309,10 +315,10 @@ cleanup1:
        return -ENOMEM;
 }
 
-static int
+static inline int
 address_needs_mapping(struct device *hwdev, dma_addr_t addr, size_t size)
 {
-       return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size);
+       return swiotlb_arch_address_needs_mapping(hwdev, addr, size);
 }
 
 static inline int range_needs_mapping(phys_addr_t paddr, size_t size)
@@ -341,7 +347,7 @@ static void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
                unsigned long flags;
 
                while (size) {
-                       sz = min(PAGE_SIZE - offset, size);
+                       sz = min_t(size_t, PAGE_SIZE - offset, size);
 
                        local_irq_save(flags);
                        buffer = kmap_atomic(pfn_to_page(pfn),
@@ -476,7 +482,7 @@ found:
  * dma_addr is the kernel virtual address of the bounce buffer to unmap.
  */
 static void
-unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
+do_unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
 {
        unsigned long flags;
        int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
@@ -560,7 +566,6 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                                   size)) {
                /*
                 * The allocated memory isn't reachable by the device.
-                * Fall back on swiotlb_map_single().
                 */
                free_pages((unsigned long) ret, order);
                ret = NULL;
@@ -568,9 +573,8 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
        if (!ret) {
                /*
                 * We are either out of memory or the device can't DMA
-                * to GFP_DMA memory; fall back on
-                * swiotlb_map_single(), which will grab memory from
-                * the lowest available address range.
+                * to GFP_DMA memory; fall back on map_single(), which
+                * will grab memory from the lowest available address range.
                 */
                ret = map_single(hwdev, 0, size, DMA_FROM_DEVICE);
                if (!ret)
@@ -587,7 +591,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                       (unsigned long long)dev_addr);
 
                /* DMA_TO_DEVICE to avoid memcpy in unmap_single */
-               unmap_single(hwdev, ret, size, DMA_TO_DEVICE);
+               do_unmap_single(hwdev, ret, size, DMA_TO_DEVICE);
                return NULL;
        }
        *dma_handle = dev_addr;
@@ -604,7 +608,7 @@ swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
                free_pages((unsigned long) vaddr, get_order(size));
        else
                /* DMA_TO_DEVICE to avoid memcpy in unmap_single */
-               unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE);
+               do_unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE);
 }
 EXPORT_SYMBOL(swiotlb_free_coherent);
 
@@ -634,7 +638,7 @@ swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
  * physical address to use is returned.
  *
  * Once the device is given the dma address, the device owns this memory until
- * either swiotlb_unmap_single or swiotlb_dma_sync_single is performed.
+ * either swiotlb_unmap_page or swiotlb_dma_sync_single is performed.
  */
 dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
                            unsigned long offset, size_t size,
@@ -642,18 +646,17 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
                            struct dma_attrs *attrs)
 {
        phys_addr_t phys = page_to_phys(page) + offset;
-       void *ptr = page_address(page) + offset;
        dma_addr_t dev_addr = swiotlb_phys_to_bus(dev, phys);
        void *map;
 
        BUG_ON(dir == DMA_NONE);
        /*
-        * If the pointer passed in happens to be in the device's DMA window,
+        * If the address happens to be in the device's DMA window,
         * we can safely return the device addr and not worry about bounce
         * buffering it.
         */
        if (!address_needs_mapping(dev, dev_addr, size) &&
-           !range_needs_mapping(virt_to_phys(ptr), size))
+           !range_needs_mapping(phys, size))
                return dev_addr;
 
        /*
@@ -679,23 +682,35 @@ EXPORT_SYMBOL_GPL(swiotlb_map_page);
 
 /*
  * Unmap a single streaming mode DMA translation.  The dma_addr and size must
- * match what was provided for in a previous swiotlb_map_single call.  All
+ * match what was provided for in a previous swiotlb_map_page call.  All
  * other usages are undefined.
  *
  * After this call, reads by the cpu to the buffer are guaranteed to see
  * whatever the device wrote there.
  */
+static void unmap_single(struct device *hwdev, dma_addr_t dev_addr,
+                        size_t size, int dir)
+{
+       char *dma_addr = swiotlb_bus_to_virt(hwdev, dev_addr);
+
+       BUG_ON(dir == DMA_NONE);
+
+       if (is_swiotlb_buffer(dma_addr)) {
+               do_unmap_single(hwdev, dma_addr, size, dir);
+               return;
+       }
+
+       if (dir != DMA_FROM_DEVICE)
+               return;
+
+       dma_mark_clean(dma_addr, size);
+}
+
 void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
                        size_t size, enum dma_data_direction dir,
                        struct dma_attrs *attrs)
 {
-       char *dma_addr = swiotlb_bus_to_virt(dev_addr);
-
-       BUG_ON(dir == DMA_NONE);
-       if (is_swiotlb_buffer(dma_addr))
-               unmap_single(hwdev, dma_addr, size, dir);
-       else if (dir == DMA_FROM_DEVICE)
-               dma_mark_clean(dma_addr, size);
+       unmap_single(hwdev, dev_addr, size, dir);
 }
 EXPORT_SYMBOL_GPL(swiotlb_unmap_page);
 
@@ -703,7 +718,7 @@ EXPORT_SYMBOL_GPL(swiotlb_unmap_page);
  * Make physical memory consistent for a single streaming mode DMA translation
  * after a transfer.
  *
- * If you perform a swiotlb_map_single() but wish to interrogate the buffer
+ * If you perform a swiotlb_map_page() but wish to interrogate the buffer
  * using the cpu, yet do not wish to teardown the dma mapping, you must
  * call this function before doing so.  At the next point you give the dma
  * address back to the card, you must first perform a
@@ -713,13 +728,19 @@ static void
 swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
                    size_t size, int dir, int target)
 {
-       char *dma_addr = swiotlb_bus_to_virt(dev_addr);
+       char *dma_addr = swiotlb_bus_to_virt(hwdev, dev_addr);
 
        BUG_ON(dir == DMA_NONE);
-       if (is_swiotlb_buffer(dma_addr))
+
+       if (is_swiotlb_buffer(dma_addr)) {
                sync_single(hwdev, dma_addr, size, dir, target);
-       else if (dir == DMA_FROM_DEVICE)
-               dma_mark_clean(dma_addr, size);
+               return;
+       }
+
+       if (dir != DMA_FROM_DEVICE)
+               return;
+
+       dma_mark_clean(dma_addr, size);
 }
 
 void
@@ -746,13 +767,7 @@ swiotlb_sync_single_range(struct device *hwdev, dma_addr_t dev_addr,
                          unsigned long offset, size_t size,
                          int dir, int target)
 {
-       char *dma_addr = swiotlb_bus_to_virt(dev_addr) + offset;
-
-       BUG_ON(dir == DMA_NONE);
-       if (is_swiotlb_buffer(dma_addr))
-               sync_single(hwdev, dma_addr, size, dir, target);
-       else if (dir == DMA_FROM_DEVICE)
-               dma_mark_clean(dma_addr, size);
+       swiotlb_sync_single(hwdev, dev_addr + offset, size, dir, target);
 }
 
 void
@@ -777,7 +792,7 @@ EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_device);
 
 /*
  * Map a set of buffers described by scatterlist in streaming mode for DMA.
- * This is the scatter-gather version of the above swiotlb_map_single
+ * This is the scatter-gather version of the above swiotlb_map_page
  * interface.  Here the scatter gather list elements are each tagged with the
  * appropriate dma address and length.  They are obtained via
  * sg_dma_{address,length}(SG).
@@ -788,7 +803,7 @@ EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_device);
  *       The routine returns the number of addr/length pairs actually
  *       used, at most nents.
  *
- * Device ownership issues as mentioned above for swiotlb_map_single are the
+ * Device ownership issues as mentioned above for swiotlb_map_page are the
  * same here.
  */
 int
@@ -836,7 +851,7 @@ EXPORT_SYMBOL(swiotlb_map_sg);
 
 /*
  * Unmap a set of streaming mode DMA translations.  Again, cpu read rules
- * concerning calls here are the same as for swiotlb_unmap_single() above.
+ * concerning calls here are the same as for swiotlb_unmap_page() above.
  */
 void
 swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
@@ -847,13 +862,9 @@ swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
 
        BUG_ON(dir == DMA_NONE);
 
-       for_each_sg(sgl, sg, nelems, i) {
-               if (sg->dma_address != swiotlb_phys_to_bus(hwdev, sg_phys(sg)))
-                       unmap_single(hwdev, swiotlb_bus_to_virt(sg->dma_address),
-                                    sg->dma_length, dir);
-               else if (dir == DMA_FROM_DEVICE)
-                       dma_mark_clean(swiotlb_bus_to_virt(sg->dma_address), sg->dma_length);
-       }
+       for_each_sg(sgl, sg, nelems, i)
+               unmap_single(hwdev, sg->dma_address, sg->dma_length, dir);
+
 }
 EXPORT_SYMBOL(swiotlb_unmap_sg_attrs);
 
@@ -879,15 +890,9 @@ swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sgl,
        struct scatterlist *sg;
        int i;
 
-       BUG_ON(dir == DMA_NONE);
-
-       for_each_sg(sgl, sg, nelems, i) {
-               if (sg->dma_address != swiotlb_phys_to_bus(hwdev, sg_phys(sg)))
-                       sync_single(hwdev, swiotlb_bus_to_virt(sg->dma_address),
+       for_each_sg(sgl, sg, nelems, i)
+               swiotlb_sync_single(hwdev, sg->dma_address,
                                    sg->dma_length, dir, target);
-               else if (dir == DMA_FROM_DEVICE)
-                       dma_mark_clean(swiotlb_bus_to_virt(sg->dma_address), sg->dma_length);
-       }
 }
 
 void
index 7536acea135ba4069c1dc04ad36d5024ac747d8c..756ccafa9cec04ada5c940f7031e6dd56aeb7837 100644 (file)
@@ -408,6 +408,8 @@ enum format_type {
        FORMAT_TYPE_LONG_LONG,
        FORMAT_TYPE_ULONG,
        FORMAT_TYPE_LONG,
+       FORMAT_TYPE_UBYTE,
+       FORMAT_TYPE_BYTE,
        FORMAT_TYPE_USHORT,
        FORMAT_TYPE_SHORT,
        FORMAT_TYPE_UINT,
@@ -573,12 +575,15 @@ static char *string(char *buf, char *end, char *s, struct printf_spec spec)
 }
 
 static char *symbol_string(char *buf, char *end, void *ptr,
-                               struct printf_spec spec)
+                               struct printf_spec spec, char ext)
 {
        unsigned long value = (unsigned long) ptr;
 #ifdef CONFIG_KALLSYMS
        char sym[KSYM_SYMBOL_LEN];
-       sprint_symbol(sym, value);
+       if (ext != 'f')
+               sprint_symbol(sym, value);
+       else
+               kallsyms_lookup(value, NULL, NULL, NULL, sym);
        return string(buf, end, sym, spec);
 #else
        spec.field_width = 2*sizeof(void *);
@@ -690,7 +695,8 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr,
  *
  * Right now we handle:
  *
- * - 'F' For symbolic function descriptor pointers
+ * - 'F' For symbolic function descriptor pointers with offset
+ * - 'f' For simple symbolic function names without offset
  * - 'S' For symbolic direct pointers
  * - 'R' For a struct resource pointer, it prints the range of
  *       addresses (not the name nor the flags)
@@ -713,10 +719,11 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
 
        switch (*fmt) {
        case 'F':
+       case 'f':
                ptr = dereference_function_descriptor(ptr);
                /* Fallthrough */
        case 'S':
-               return symbol_string(buf, end, ptr, spec);
+               return symbol_string(buf, end, ptr, spec, *fmt);
        case 'R':
                return resource_string(buf, end, ptr, spec);
        case 'm':
@@ -853,11 +860,15 @@ qualifier:
        spec->qualifier = -1;
        if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
            *fmt == 'Z' || *fmt == 'z' || *fmt == 't') {
-               spec->qualifier = *fmt;
-               ++fmt;
-               if (spec->qualifier == 'l' && *fmt == 'l') {
-                       spec->qualifier = 'L';
-                       ++fmt;
+               spec->qualifier = *fmt++;
+               if (unlikely(spec->qualifier == *fmt)) {
+                       if (spec->qualifier == 'l') {
+                               spec->qualifier = 'L';
+                               ++fmt;
+                       } else if (spec->qualifier == 'h') {
+                               spec->qualifier = 'H';
+                               ++fmt;
+                       }
                }
        }
 
@@ -919,6 +930,11 @@ qualifier:
                spec->type = FORMAT_TYPE_SIZE_T;
        } else if (spec->qualifier == 't') {
                spec->type = FORMAT_TYPE_PTRDIFF;
+       } else if (spec->qualifier == 'H') {
+               if (spec->flags & SIGN)
+                       spec->type = FORMAT_TYPE_BYTE;
+               else
+                       spec->type = FORMAT_TYPE_UBYTE;
        } else if (spec->qualifier == 'h') {
                if (spec->flags & SIGN)
                        spec->type = FORMAT_TYPE_SHORT;
@@ -943,7 +959,8 @@ qualifier:
  *
  * This function follows C99 vsnprintf, but has some extensions:
  * %pS output the name of a text symbol
- * %pF output the name of a function pointer
+ * %pF output the name of a function pointer with its offset
+ * %pf output the name of a function pointer without its offset
  * %pR output the address range in a struct resource
  *
  * The return value is the number of characters which would
@@ -1087,6 +1104,12 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                        case FORMAT_TYPE_PTRDIFF:
                                num = va_arg(args, ptrdiff_t);
                                break;
+                       case FORMAT_TYPE_UBYTE:
+                               num = (unsigned char) va_arg(args, int);
+                               break;
+                       case FORMAT_TYPE_BYTE:
+                               num = (signed char) va_arg(args, int);
+                               break;
                        case FORMAT_TYPE_USHORT:
                                num = (unsigned short) va_arg(args, int);
                                break;
@@ -1363,6 +1386,10 @@ do {                                                                     \
                        case FORMAT_TYPE_PTRDIFF:
                                save_arg(ptrdiff_t);
                                break;
+                       case FORMAT_TYPE_UBYTE:
+                       case FORMAT_TYPE_BYTE:
+                               save_arg(char);
+                               break;
                        case FORMAT_TYPE_USHORT:
                        case FORMAT_TYPE_SHORT:
                                save_arg(short);
@@ -1391,7 +1418,8 @@ EXPORT_SYMBOL_GPL(vbin_printf);
  *
  * The format follows C99 vsnprintf, but has some extensions:
  * %pS output the name of a text symbol
- * %pF output the name of a function pointer
+ * %pF output the name of a function pointer with its offset
+ * %pf output the name of a function pointer without its offset
  * %pR output the address range in a struct resource
  * %n is ignored
  *
@@ -1538,6 +1566,12 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
                        case FORMAT_TYPE_PTRDIFF:
                                num = get_arg(ptrdiff_t);
                                break;
+                       case FORMAT_TYPE_UBYTE:
+                               num = get_arg(unsigned char);
+                               break;
+                       case FORMAT_TYPE_BYTE:
+                               num = get_arg(signed char);
+                               break;
                        case FORMAT_TYPE_USHORT:
                                num = get_arg(unsigned short);
                                break;
index c2b57d81e153077bec9bc8be39af8bb658537065..71830ba7b986a8e4da4b448793791bf2bc65c245 100644 (file)
@@ -226,6 +226,25 @@ config HAVE_MLOCKED_PAGE_BIT
 config MMU_NOTIFIER
        bool
 
+config DEFAULT_MMAP_MIN_ADDR
+        int "Low address space to protect from user allocation"
+        default 4096
+        help
+         This is the portion of low virtual memory which should be protected
+         from userspace allocation.  Keeping a user from writing to low pages
+         can help reduce the impact of kernel NULL pointer bugs.
+
+         For most ia64, ppc64 and x86 users with lots of address space
+         a value of 65536 is reasonable and should cause no problems.
+         On arm and other archs it should not be higher than 32768.
+         Programs which use vm86 functionality would either need additional
+         permissions from either the LSM or the capabilities module or have
+         this protection disabled.
+
+         This value can be changed after boot using the
+         /proc/sys/vm/mmap_min_addr tunable.
+
+
 config NOMMU_INITIAL_TRIM_EXCESS
        int "Turn on mmap() excess space trimming before booting"
        depends on !MMU
index e590272fe7a8f3e40acb21059bb0082f74354f26..4ebe3ea837952a3f784159a9009212c3506e4a0f 100644 (file)
 #include <linux/hash.h>
 #include <linux/highmem.h>
 #include <linux/blktrace_api.h>
-#include <trace/block.h>
 #include <asm/tlbflush.h>
 
+#include <trace/events/block.h>
+
 #define POOL_SIZE      64
 #define ISA_POOL_SIZE  16
 
 static mempool_t *page_pool, *isa_page_pool;
 
-DEFINE_TRACE(block_bio_bounce);
-
 #ifdef CONFIG_HIGHMEM
 static __init int init_emergency_pool(void)
 {
@@ -192,7 +191,7 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig,
                /*
                 * is destination page below bounce pfn?
                 */
-               if (page_to_pfn(page) <= q->bounce_pfn)
+               if (page_to_pfn(page) <= queue_bounce_pfn(q))
                        continue;
 
                /*
@@ -284,7 +283,7 @@ void blk_queue_bounce(struct request_queue *q, struct bio **bio_orig)
         * don't waste time iterating over bio segments
         */
        if (!(q->bounce_gfp & GFP_DMA)) {
-               if (q->bounce_pfn >= blk_max_pfn)
+               if (queue_bounce_pfn(q) >= blk_max_pfn)
                        return;
                pool = page_pool;
        } else {
index cbe9e0581b75dcaf06335ccc017a68789d6247d2..ac130433c7d35da275b1ad081bfddd9fbf017173 100644 (file)
@@ -629,52 +629,43 @@ void user_shm_unlock(size_t size, struct user_struct *user)
        free_uid(user);
 }
 
-void *alloc_locked_buffer(size_t size)
+int account_locked_memory(struct mm_struct *mm, struct rlimit *rlim,
+                         size_t size)
 {
-       unsigned long rlim, vm, pgsz;
-       void *buffer = NULL;
+       unsigned long lim, vm, pgsz;
+       int error = -ENOMEM;
 
        pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT;
 
-       down_write(&current->mm->mmap_sem);
-
-       rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
-       vm   = current->mm->total_vm + pgsz;
-       if (rlim < vm)
-               goto out;
+       down_write(&mm->mmap_sem);
 
-       rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
-       vm   = current->mm->locked_vm + pgsz;
-       if (rlim < vm)
+       lim = rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
+       vm   = mm->total_vm + pgsz;
+       if (lim < vm)
                goto out;
 
-       buffer = kzalloc(size, GFP_KERNEL);
-       if (!buffer)
+       lim = rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
+       vm   = mm->locked_vm + pgsz;
+       if (lim < vm)
                goto out;
 
-       current->mm->total_vm  += pgsz;
-       current->mm->locked_vm += pgsz;
+       mm->total_vm  += pgsz;
+       mm->locked_vm += pgsz;
 
+       error = 0;
  out:
-       up_write(&current->mm->mmap_sem);
-       return buffer;
+       up_write(&mm->mmap_sem);
+       return error;
 }
 
-void release_locked_buffer(void *buffer, size_t size)
+void refund_locked_memory(struct mm_struct *mm, size_t size)
 {
        unsigned long pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT;
 
-       down_write(&current->mm->mmap_sem);
-
-       current->mm->total_vm  -= pgsz;
-       current->mm->locked_vm -= pgsz;
-
-       up_write(&current->mm->mmap_sem);
-}
+       down_write(&mm->mmap_sem);
 
-void free_locked_buffer(void *buffer, size_t size)
-{
-       release_locked_buffer(buffer, size);
+       mm->total_vm  -= pgsz;
+       mm->locked_vm -= pgsz;
 
-       kfree(buffer);
+       up_write(&mm->mmap_sem);
 }
index 6b7b1a95944bf267bd21cd981703280fe25a39e9..2b43fa1aa3c8318cbaa5e6b80da0c26944b90b4a 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -87,6 +87,9 @@ int sysctl_overcommit_ratio = 50;     /* default is 50% */
 int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
 struct percpu_counter vm_committed_as;
 
+/* amount of vm to protect from userspace access */
+unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
+
 /*
  * Check that a process has enough memory to allocate a new virtual
  * mapping. 0 means there is enough memory for the allocation to
index b571ef707428c5e171fa27b7fc09d0212018c5df..2fd2ad5da98e5d82e751b76f4e6369c57f20e6db 100644 (file)
@@ -69,6 +69,9 @@ int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT;
 int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS;
 int heap_stack_gap = 0;
 
+/* amount of vm to protect from userspace access */
+unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
+
 atomic_long_t mmap_pages_allocated;
 
 EXPORT_SYMBOL(mem_map);
index fe753ecf2aa5fd234dedb6916c333055bcfe8b36..474c7e9dd51ac66f97b027bf5b384a1bacd42da7 100644 (file)
@@ -149,10 +149,6 @@ static unsigned long __meminitdata dma_reserve;
   static int __meminitdata nr_nodemap_entries;
   static unsigned long __meminitdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES];
   static unsigned long __meminitdata arch_zone_highest_possible_pfn[MAX_NR_ZONES];
-#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
-  static unsigned long __meminitdata node_boundary_start_pfn[MAX_NUMNODES];
-  static unsigned long __meminitdata node_boundary_end_pfn[MAX_NUMNODES];
-#endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */
   static unsigned long __initdata required_kernelcore;
   static unsigned long __initdata required_movablecore;
   static unsigned long __meminitdata zone_movable_pfn[MAX_NUMNODES];
@@ -3102,64 +3098,6 @@ void __init sparse_memory_present_with_active_regions(int nid)
                                early_node_map[i].end_pfn);
 }
 
-/**
- * push_node_boundaries - Push node boundaries to at least the requested boundary
- * @nid: The nid of the node to push the boundary for
- * @start_pfn: The start pfn of the node
- * @end_pfn: The end pfn of the node
- *
- * In reserve-based hot-add, mem_map is allocated that is unused until hotadd
- * time. Specifically, on x86_64, SRAT will report ranges that can potentially
- * be hotplugged even though no physical memory exists. This function allows
- * an arch to push out the node boundaries so mem_map is allocated that can
- * be used later.
- */
-#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
-void __init push_node_boundaries(unsigned int nid,
-               unsigned long start_pfn, unsigned long end_pfn)
-{
-       mminit_dprintk(MMINIT_TRACE, "zoneboundary",
-                       "Entering push_node_boundaries(%u, %lu, %lu)\n",
-                       nid, start_pfn, end_pfn);
-
-       /* Initialise the boundary for this node if necessary */
-       if (node_boundary_end_pfn[nid] == 0)
-               node_boundary_start_pfn[nid] = -1UL;
-
-       /* Update the boundaries */
-       if (node_boundary_start_pfn[nid] > start_pfn)
-               node_boundary_start_pfn[nid] = start_pfn;
-       if (node_boundary_end_pfn[nid] < end_pfn)
-               node_boundary_end_pfn[nid] = end_pfn;
-}
-
-/* If necessary, push the node boundary out for reserve hotadd */
-static void __meminit account_node_boundary(unsigned int nid,
-               unsigned long *start_pfn, unsigned long *end_pfn)
-{
-       mminit_dprintk(MMINIT_TRACE, "zoneboundary",
-                       "Entering account_node_boundary(%u, %lu, %lu)\n",
-                       nid, *start_pfn, *end_pfn);
-
-       /* Return if boundary information has not been provided */
-       if (node_boundary_end_pfn[nid] == 0)
-               return;
-
-       /* Check the boundaries and update if necessary */
-       if (node_boundary_start_pfn[nid] < *start_pfn)
-               *start_pfn = node_boundary_start_pfn[nid];
-       if (node_boundary_end_pfn[nid] > *end_pfn)
-               *end_pfn = node_boundary_end_pfn[nid];
-}
-#else
-void __init push_node_boundaries(unsigned int nid,
-               unsigned long start_pfn, unsigned long end_pfn) {}
-
-static void __meminit account_node_boundary(unsigned int nid,
-               unsigned long *start_pfn, unsigned long *end_pfn) {}
-#endif
-
-
 /**
  * get_pfn_range_for_nid - Return the start and end page frames for a node
  * @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned.
@@ -3185,9 +3123,6 @@ void __meminit get_pfn_range_for_nid(unsigned int nid,
 
        if (*start_pfn == -1UL)
                *start_pfn = 0;
-
-       /* Push the node boundaries out if requested */
-       account_node_boundary(nid, start_pfn, end_pfn);
 }
 
 /*
@@ -3793,10 +3728,6 @@ void __init remove_all_active_ranges(void)
 {
        memset(early_node_map, 0, sizeof(early_node_map));
        nr_nodemap_entries = 0;
-#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
-       memset(node_boundary_start_pfn, 0, sizeof(node_boundary_start_pfn));
-       memset(node_boundary_end_pfn, 0, sizeof(node_boundary_end_pfn));
-#endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */
 }
 
 /* Compare two active node_active_regions */
index 1aa5d8fbca121d434f3cb812e10569f1b8e05f82..c0b2c1a76e81c280398b27ed310b1e03500e3a23 100644 (file)
@@ -23,7 +23,7 @@
  * Allocation is done in offset-size areas of single unit space.  Ie,
  * an area of 512 bytes at 6k in c1 occupies 512 bytes at 6k of c1:u0,
  * c1:u1, c1:u2 and c1:u3.  Percpu access can be done by configuring
- * percpu base registers UNIT_SIZE apart.
+ * percpu base registers pcpu_unit_size apart.
  *
  * There are usually many small percpu allocations many of them as
  * small as 4 bytes.  The allocator organizes chunks into lists
@@ -38,8 +38,8 @@
  * region and negative allocated.  Allocation inside a chunk is done
  * by scanning this map sequentially and serving the first matching
  * entry.  This is mostly copied from the percpu_modalloc() allocator.
- * Chunks are also linked into a rb tree to ease address to chunk
- * mapping during free.
+ * Chunks can be determined from the address using the index field
+ * in the page struct. The index field contains a pointer to the chunk.
  *
  * To use this allocator, arch code should do the followings.
  *
@@ -61,7 +61,6 @@
 #include <linux/mutex.h>
 #include <linux/percpu.h>
 #include <linux/pfn.h>
-#include <linux/rbtree.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/vmalloc.h>
@@ -88,7 +87,6 @@
 
 struct pcpu_chunk {
        struct list_head        list;           /* linked to pcpu_slot lists */
-       struct rb_node          rb_node;        /* key is chunk->vm->addr */
        int                     free_size;      /* free bytes in the chunk */
        int                     contig_hint;    /* max contiguous size hint */
        struct vm_struct        *vm;            /* mapped vmalloc region */
@@ -110,9 +108,21 @@ static size_t pcpu_chunk_struct_size __read_mostly;
 void *pcpu_base_addr __read_mostly;
 EXPORT_SYMBOL_GPL(pcpu_base_addr);
 
-/* optional reserved chunk, only accessible for reserved allocations */
+/*
+ * The first chunk which always exists.  Note that unlike other
+ * chunks, this one can be allocated and mapped in several different
+ * ways and thus often doesn't live in the vmalloc area.
+ */
+static struct pcpu_chunk *pcpu_first_chunk;
+
+/*
+ * Optional reserved chunk.  This chunk reserves part of the first
+ * chunk and serves it for reserved allocations.  The amount of
+ * reserved offset is in pcpu_reserved_chunk_limit.  When reserved
+ * area doesn't exist, the following variables contain NULL and 0
+ * respectively.
+ */
 static struct pcpu_chunk *pcpu_reserved_chunk;
-/* offset limit of the reserved chunk */
 static int pcpu_reserved_chunk_limit;
 
 /*
@@ -121,7 +131,7 @@ static int pcpu_reserved_chunk_limit;
  * There are two locks - pcpu_alloc_mutex and pcpu_lock.  The former
  * protects allocation/reclaim paths, chunks and chunk->page arrays.
  * The latter is a spinlock and protects the index data structures -
- * chunk slots, rbtree, chunks and area maps in chunks.
+ * chunk slots, chunks and area maps in chunks.
  *
  * During allocation, pcpu_alloc_mutex is kept locked all the time and
  * pcpu_lock is grabbed and released as necessary.  All actual memory
@@ -140,7 +150,6 @@ static DEFINE_MUTEX(pcpu_alloc_mutex);      /* protects whole alloc and reclaim */
 static DEFINE_SPINLOCK(pcpu_lock);     /* protects index data structures */
 
 static struct list_head *pcpu_slot __read_mostly; /* chunk list slots */
-static struct rb_root pcpu_addr_root = RB_ROOT;        /* chunks by address */
 
 /* reclaim work to release fully free chunks, scheduled from free path */
 static void pcpu_reclaim(struct work_struct *work);
@@ -191,6 +200,18 @@ static bool pcpu_chunk_page_occupied(struct pcpu_chunk *chunk,
        return *pcpu_chunk_pagep(chunk, 0, page_idx) != NULL;
 }
 
+/* set the pointer to a chunk in a page struct */
+static void pcpu_set_page_chunk(struct page *page, struct pcpu_chunk *pcpu)
+{
+       page->index = (unsigned long)pcpu;
+}
+
+/* obtain pointer to a chunk from a page struct */
+static struct pcpu_chunk *pcpu_get_page_chunk(struct page *page)
+{
+       return (struct pcpu_chunk *)page->index;
+}
+
 /**
  * pcpu_mem_alloc - allocate memory
  * @size: bytes to allocate
@@ -257,93 +278,26 @@ static void pcpu_chunk_relocate(struct pcpu_chunk *chunk, int oslot)
        }
 }
 
-static struct rb_node **pcpu_chunk_rb_search(void *addr,
-                                            struct rb_node **parentp)
-{
-       struct rb_node **p = &pcpu_addr_root.rb_node;
-       struct rb_node *parent = NULL;
-       struct pcpu_chunk *chunk;
-
-       while (*p) {
-               parent = *p;
-               chunk = rb_entry(parent, struct pcpu_chunk, rb_node);
-
-               if (addr < chunk->vm->addr)
-                       p = &(*p)->rb_left;
-               else if (addr > chunk->vm->addr)
-                       p = &(*p)->rb_right;
-               else
-                       break;
-       }
-
-       if (parentp)
-               *parentp = parent;
-       return p;
-}
-
 /**
- * pcpu_chunk_addr_search - search for chunk containing specified address
- * @addr: address to search for
- *
- * Look for chunk which might contain @addr.  More specifically, it
- * searchs for the chunk with the highest start address which isn't
- * beyond @addr.
- *
- * CONTEXT:
- * pcpu_lock.
+ * pcpu_chunk_addr_search - determine chunk containing specified address
+ * @addr: address for which the chunk needs to be determined.
  *
  * RETURNS:
  * The address of the found chunk.
  */
 static struct pcpu_chunk *pcpu_chunk_addr_search(void *addr)
 {
-       struct rb_node *n, *parent;
-       struct pcpu_chunk *chunk;
+       void *first_start = pcpu_first_chunk->vm->addr;
 
-       /* is it in the reserved chunk? */
-       if (pcpu_reserved_chunk) {
-               void *start = pcpu_reserved_chunk->vm->addr;
-
-               if (addr >= start && addr < start + pcpu_reserved_chunk_limit)
+       /* is it in the first chunk? */
+       if (addr >= first_start && addr < first_start + pcpu_chunk_size) {
+               /* is it in the reserved area? */
+               if (addr < first_start + pcpu_reserved_chunk_limit)
                        return pcpu_reserved_chunk;
+               return pcpu_first_chunk;
        }
 
-       /* nah... search the regular ones */
-       n = *pcpu_chunk_rb_search(addr, &parent);
-       if (!n) {
-               /* no exactly matching chunk, the parent is the closest */
-               n = parent;
-               BUG_ON(!n);
-       }
-       chunk = rb_entry(n, struct pcpu_chunk, rb_node);
-
-       if (addr < chunk->vm->addr) {
-               /* the parent was the next one, look for the previous one */
-               n = rb_prev(n);
-               BUG_ON(!n);
-               chunk = rb_entry(n, struct pcpu_chunk, rb_node);
-       }
-
-       return chunk;
-}
-
-/**
- * pcpu_chunk_addr_insert - insert chunk into address rb tree
- * @new: chunk to insert
- *
- * Insert @new into address rb tree.
- *
- * CONTEXT:
- * pcpu_lock.
- */
-static void pcpu_chunk_addr_insert(struct pcpu_chunk *new)
-{
-       struct rb_node **p, *parent;
-
-       p = pcpu_chunk_rb_search(new->vm->addr, &parent);
-       BUG_ON(*p);
-       rb_link_node(&new->rb_node, parent, p);
-       rb_insert_color(&new->rb_node, &pcpu_addr_root);
+       return pcpu_get_page_chunk(vmalloc_to_page(addr));
 }
 
 /**
@@ -755,6 +709,7 @@ static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int off, int size)
                                                  alloc_mask, 0);
                        if (!*pagep)
                                goto err;
+                       pcpu_set_page_chunk(*pagep, chunk);
                }
        }
 
@@ -879,7 +834,6 @@ restart:
 
        spin_lock_irq(&pcpu_lock);
        pcpu_chunk_relocate(chunk, -1);
-       pcpu_chunk_addr_insert(chunk);
        goto restart;
 
 area_found:
@@ -968,7 +922,6 @@ static void pcpu_reclaim(struct work_struct *work)
                if (chunk == list_first_entry(head, struct pcpu_chunk, list))
                        continue;
 
-               rb_erase(&chunk->rb_node, &pcpu_addr_root);
                list_move(&chunk->list, &todo);
        }
 
@@ -1147,7 +1100,8 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn,
 
        if (reserved_size) {
                schunk->free_size = reserved_size;
-               pcpu_reserved_chunk = schunk;   /* not for dynamic alloc */
+               pcpu_reserved_chunk = schunk;
+               pcpu_reserved_chunk_limit = static_size + reserved_size;
        } else {
                schunk->free_size = dyn_size;
                dyn_size = 0;                   /* dynamic area covered */
@@ -1158,8 +1112,6 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn,
        if (schunk->free_size)
                schunk->map[schunk->map_used++] = schunk->free_size;
 
-       pcpu_reserved_chunk_limit = static_size + schunk->free_size;
-
        /* init dynamic chunk if necessary */
        if (dyn_size) {
                dchunk = alloc_bootmem(sizeof(struct pcpu_chunk));
@@ -1226,13 +1178,8 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn,
        }
 
        /* link the first chunk in */
-       if (!dchunk) {
-               pcpu_chunk_relocate(schunk, -1);
-               pcpu_chunk_addr_insert(schunk);
-       } else {
-               pcpu_chunk_relocate(dchunk, -1);
-               pcpu_chunk_addr_insert(dchunk);
-       }
+       pcpu_first_chunk = dchunk ?: schunk;
+       pcpu_chunk_relocate(pcpu_first_chunk, -1);
 
        /* we're done */
        pcpu_base_addr = (void *)pcpu_chunk_addr(schunk, 0, 0);
index b25f95ce3db76bb3e04658b3d6a0273729fbae55..0132fbd45a23837d5abc3cdea527a6d3cafb53a7 100644 (file)
@@ -2659,6 +2659,7 @@ struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags)
        if (error)
                goto close_file;
 #endif
+       ima_counts_get(file);
        return file;
 
 close_file:
@@ -2684,7 +2685,6 @@ int shmem_zero_setup(struct vm_area_struct *vma)
        if (IS_ERR(file))
                return PTR_ERR(file);
 
-       ima_shm_check(file);
        if (vma->vm_file)
                fput(vma->vm_file);
        vma->vm_file = file;
index 9a90b00d2f9140e2aaa67ecb949e33d89431e9c5..f85831da9080d22e4abe0b2e2f2405cd067a0d85 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
 #include       <linux/cpu.h>
 #include       <linux/sysctl.h>
 #include       <linux/module.h>
-#include       <trace/kmemtrace.h>
+#include       <linux/kmemtrace.h>
 #include       <linux/rcupdate.h>
 #include       <linux/string.h>
 #include       <linux/uaccess.h>
index f92e66d558bd3608f5c758d7b7c39748cf936f51..9b1737b0787bf53740fd538e697df549e140620b 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -66,7 +66,7 @@
 #include <linux/module.h>
 #include <linux/rcupdate.h>
 #include <linux/list.h>
-#include <trace/kmemtrace.h>
+#include <linux/kmemtrace.h>
 #include <asm/atomic.h>
 
 /*
index 65ffda5934b09b8220e9a00332945dc19ba88de6..5e805a6fe36c46a200bc9d1ded7224bed5fce3ba 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -17,7 +17,7 @@
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#include <trace/kmemtrace.h>
+#include <linux/kmemtrace.h>
 #include <linux/cpu.h>
 #include <linux/cpuset.h>
 #include <linux/mempolicy.h>
index 55bef160b9f1484c032220b506f4ebfaeffe9a47..abc65aa7cdfc7bcfc76817afe2451cce7a4ece3e 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -4,9 +4,11 @@
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/sched.h>
-#include <linux/tracepoint.h>
 #include <asm/uaccess.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/kmem.h>
+
 /**
  * kstrdup - allocate space for and copy an existing string
  * @s: the string to duplicate
@@ -255,13 +257,6 @@ int __attribute__((weak)) get_user_pages_fast(unsigned long start,
 EXPORT_SYMBOL_GPL(get_user_pages_fast);
 
 /* Tracepoints definitions. */
-DEFINE_TRACE(kmalloc);
-DEFINE_TRACE(kmem_cache_alloc);
-DEFINE_TRACE(kmalloc_node);
-DEFINE_TRACE(kmem_cache_alloc_node);
-DEFINE_TRACE(kfree);
-DEFINE_TRACE(kmem_cache_free);
-
 EXPORT_TRACEPOINT_SYMBOL(kmalloc);
 EXPORT_TRACEPOINT_SYMBOL(kmem_cache_alloc);
 EXPORT_TRACEPOINT_SYMBOL(kmalloc_node);
index 9fd0dc3cca99f5bad5af9fdbc189c528573fcc90..b75b6cea49dab47cbca9098a259ac44e4e51b4c8 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/bitops.h>
 #include <net/genetlink.h>
 
-#include <trace/skb.h>
+#include <trace/events/skb.h>
 
 #include <asm/unaligned.h>
 
index c8fb45665e4f4af4cf6ced67fe90fff64f74e3ed..499a67eaf3ae201262c4a2e53f20870721b8f184 100644 (file)
 #include <linux/workqueue.h>
 #include <linux/netlink.h>
 #include <linux/net_dropmon.h>
-#include <trace/skb.h>
 
 #include <asm/unaligned.h>
 #include <asm/bitops.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/skb.h>
 
-DEFINE_TRACE(kfree_skb);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kfree_skb);
index e505b5392e1e511b278eda64e71914750ffc6577..c2e4fb8f3546c06a39b22b8c8538ecdf7187c3e7 100644 (file)
@@ -65,7 +65,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <trace/skb.h>
+#include <trace/events/skb.h>
 
 #include "kmap_skb.h"
 
index 4b02f5a0e6560f4c886d413409d5507ffe6b0356..b75d28cba3f75fef74d90d01b2fb8990984a1c55 100644 (file)
@@ -19,6 +19,12 @@ config SAMPLE_TRACEPOINTS
        help
          This build tracepoints example modules.
 
+config SAMPLE_TRACE_EVENTS
+       tristate "Build trace_events examples -- loadable modules only"
+       depends on EVENT_TRACING && m
+       help
+         This build trace event example modules.
+
 config SAMPLE_KOBJECT
        tristate "Build kobject examples"
        help
index 10eaca89fe17913875f90cf0354a9478978db018..13e4b470b5399b41a8f140b935bade02511c688e 100644 (file)
@@ -1,3 +1,3 @@
 # Makefile for Linux samples code
 
-obj-$(CONFIG_SAMPLES)  += markers/ kobject/ kprobes/ tracepoints/
+obj-$(CONFIG_SAMPLES)  += markers/ kobject/ kprobes/ tracepoints/ trace_events/
diff --git a/samples/trace_events/Makefile b/samples/trace_events/Makefile
new file mode 100644 (file)
index 0000000..0d428dc
--- /dev/null
@@ -0,0 +1,6 @@
+# builds the trace events example kernel modules;
+# then to use one (as root):  insmod <module_name.ko>
+
+CFLAGS_trace-events-sample.o := -I$(src)
+
+obj-$(CONFIG_SAMPLE_TRACE_EVENTS) += trace-events-sample.o
diff --git a/samples/trace_events/trace-events-sample.c b/samples/trace_events/trace-events-sample.c
new file mode 100644 (file)
index 0000000..aabc4e9
--- /dev/null
@@ -0,0 +1,52 @@
+#include <linux/module.h>
+#include <linux/kthread.h>
+
+/*
+ * Any file that uses trace points, must include the header.
+ * But only one file, must include the header by defining
+ * CREATE_TRACE_POINTS first.  This will make the C code that
+ * creates the handles for the trace points.
+ */
+#define CREATE_TRACE_POINTS
+#include "trace-events-sample.h"
+
+
+static void simple_thread_func(int cnt)
+{
+       set_current_state(TASK_INTERRUPTIBLE);
+       schedule_timeout(HZ);
+       trace_foo_bar("hello", cnt);
+}
+
+static int simple_thread(void *arg)
+{
+       int cnt = 0;
+
+       while (!kthread_should_stop())
+               simple_thread_func(cnt++);
+
+       return 0;
+}
+
+static struct task_struct *simple_tsk;
+
+static int __init trace_event_init(void)
+{
+       simple_tsk = kthread_run(simple_thread, NULL, "event-sample");
+       if (IS_ERR(simple_tsk))
+               return -1;
+
+       return 0;
+}
+
+static void __exit trace_event_exit(void)
+{
+       kthread_stop(simple_tsk);
+}
+
+module_init(trace_event_init);
+module_exit(trace_event_exit);
+
+MODULE_AUTHOR("Steven Rostedt");
+MODULE_DESCRIPTION("trace-events-sample");
+MODULE_LICENSE("GPL");
diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h
new file mode 100644 (file)
index 0000000..128a897
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Notice that this file is not protected like a normal header.
+ * We also must allow for rereading of this file. The
+ *
+ *  || defined(TRACE_HEADER_MULTI_READ)
+ *
+ * serves this purpose.
+ */
+#if !defined(_TRACE_EVENT_SAMPLE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_EVENT_SAMPLE_H
+
+/*
+ * All trace headers should include tracepoint.h, until we finally
+ * make it into a standard header.
+ */
+#include <linux/tracepoint.h>
+
+/*
+ * If TRACE_SYSTEM is defined, that will be the directory created
+ * in the ftrace directory under /debugfs/tracing/events/<system>
+ *
+ * The define_trace.h belowe will also look for a file name of
+ * TRACE_SYSTEM.h where TRACE_SYSTEM is what is defined here.
+ *
+ * If you want a different system than file name, you can override
+ * the header name by defining TRACE_INCLUDE_FILE
+ *
+ * If this file was called, goofy.h, then we would define:
+ *
+ * #define TRACE_INCLUDE_FILE goofy
+ *
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM sample
+
+/*
+ * The TRACE_EVENT macro is broken up into 5 parts.
+ *
+ * name: name of the trace point. This is also how to enable the tracepoint.
+ *   A function called trace_foo_bar() will be created.
+ *
+ * proto: the prototype of the function trace_foo_bar()
+ *   Here it is trace_foo_bar(char *foo, int bar).
+ *
+ * args:  must match the arguments in the prototype.
+ *    Here it is simply "foo, bar".
+ *
+ * struct:  This defines the way the data will be stored in the ring buffer.
+ *    There are currently two types of elements. __field and __array.
+ *    a __field is broken up into (type, name). Where type can be any
+ *    type but an array.
+ *    For an array. there are three fields. (type, name, size). The
+ *    type of elements in the array, the name of the field and the size
+ *    of the array.
+ *
+ *    __array( char, foo, 10) is the same as saying   char foo[10].
+ *
+ * fast_assign: This is a C like function that is used to store the items
+ *    into the ring buffer.
+ *
+ * printk: This is a way to print out the data in pretty print. This is
+ *    useful if the system crashes and you are logging via a serial line,
+ *    the data can be printed to the console using this "printk" method.
+ *
+ * Note, that for both the assign and the printk, __entry is the handler
+ * to the data structure in the ring buffer, and is defined by the
+ * TP_STRUCT__entry.
+ */
+TRACE_EVENT(foo_bar,
+
+       TP_PROTO(char *foo, int bar),
+
+       TP_ARGS(foo, bar),
+
+       TP_STRUCT__entry(
+               __array(        char,   foo,    10              )
+               __field(        int,    bar                     )
+       ),
+
+       TP_fast_assign(
+               strncpy(__entry->foo, foo, 10);
+               __entry->bar    = bar;
+       ),
+
+       TP_printk("foo %s %d", __entry->foo, __entry->bar)
+);
+#endif
+
+/***** NOTICE! The #if protection ends here. *****/
+
+
+/*
+ * There are several ways I could have done this. If I left out the
+ * TRACE_INCLUDE_PATH, then it would default to the kernel source
+ * include/trace/events directory.
+ *
+ * I could specify a path from the define_trace.h file back to this
+ * file.
+ *
+ * #define TRACE_INCLUDE_PATH ../../samples/trace_events
+ *
+ * But I chose to simply make it use the current directory and then in
+ * the Makefile I added:
+ *
+ * CFLAGS_trace-events-sample.o := -I$(PWD)/samples/trace_events/
+ *
+ * This will make sure the current path is part of the include
+ * structure for our file so that we can find it.
+ *
+ * I could have made only the top level directory the include:
+ *
+ * CFLAGS_trace-events-sample.o := -I$(PWD)
+ *
+ * And then let the path to this directory be the TRACE_INCLUDE_PATH:
+ *
+ * #define TRACE_INCLUDE_PATH samples/trace_events
+ *
+ * But then if something defines "samples" or "trace_events" then we
+ * could risk that being converted too, and give us an unexpected
+ * result.
+ */
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH .
+/*
+ * TRACE_INCLUDE_FILE is not needed if the filename and TRACE_SYSTEM are equal
+ */
+#define TRACE_INCLUDE_FILE trace-events-sample
+#include <trace/define_trace.h>
index cba61ca403cacb644bf07fed6e11f340f90c8f50..2b706617c89a806c69b83a112f046f16046904b4 100644 (file)
@@ -188,20 +188,34 @@ cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
 # ---------------------------------------------------------------------------
 
 quiet_cmd_gzip = GZIP    $@
-cmd_gzip = gzip -f -9 < $< > $@
+cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -f -9 > $@) || \
+       (rm -f $@ ; false)
 
 
 # Bzip2
 # ---------------------------------------------------------------------------
 
-# Bzip2 does not include size in file... so we have to fake that
-size_append=$(CONFIG_SHELL) $(srctree)/scripts/bin_size
-
-quiet_cmd_bzip2 = BZIP2    $@
-cmd_bzip2 = (bzip2 -9 < $< && $(size_append) $<) > $@ || (rm -f $@ ; false)
+# Bzip2 and LZMA do not include size in file... so we have to fake that;
+# append the size as a 32-bit littleendian number as gzip does.
+size_append = echo -ne $(shell                                         \
+dec_size=0;                                                            \
+for F in $1; do                                                                \
+       fsize=$$(stat -c "%s" $$F);                                     \
+       dec_size=$$(expr $$dec_size + $$fsize);                         \
+done;                                                                  \
+printf "%08x" $$dec_size |                                             \
+       sed 's/\(..\)\(..\)\(..\)\(..\)/\\\\x\4\\\\x\3\\\\x\2\\\\x\1/g' \
+)
+
+quiet_cmd_bzip2 = BZIP2   $@
+cmd_bzip2 = (cat $(filter-out FORCE,$^) | \
+       bzip2 -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
+       (rm -f $@ ; false)
 
 # Lzma
 # ---------------------------------------------------------------------------
 
 quiet_cmd_lzma = LZMA    $@
-cmd_lzma = (lzma -9 -c $< && $(size_append) $<) >$@ || (rm -f $@ ; false)
+cmd_lzma = (cat $(filter-out FORCE,$^) | \
+       lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
+       (rm -f $@ ; false)
diff --git a/scripts/bin_size b/scripts/bin_size
deleted file mode 100644 (file)
index 43e1b36..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-
-if [ $# = 0 ] ; then
-   echo Usage: $0 file
-fi
-
-size_dec=`stat -c "%s" $1`
-size_hex_echo_string=`printf "%08x" $size_dec |
-     sed 's/\(..\)\(..\)\(..\)\(..\)/\\\\x\4\\\\x\3\\\\x\2\\\\x\1/g'`
-/bin/echo -ne $size_hex_echo_string
index 3208a3a7e7fe5e3f9ad07a20a5bb9827d099d5ae..acd8c4a8e3e0b00f24eaf3331b70156becbecf60 100755 (executable)
@@ -1828,6 +1828,25 @@ sub reset_state {
     $state = 0;
 }
 
+sub tracepoint_munge($) {
+       my $file = shift;
+       my $tracepointname = 0;
+       my $tracepointargs = 0;
+
+       if($prototype =~ m/TRACE_EVENT\((.*?),/) {
+               $tracepointname = $1;
+       }
+       if($prototype =~ m/TP_PROTO\((.*?)\)/) {
+               $tracepointargs = $1;
+       }
+       if (($tracepointname eq 0) || ($tracepointargs eq 0)) {
+               print STDERR "Warning(${file}:$.): Unrecognized tracepoint format: \n".
+                            "$prototype\n";
+       } else {
+               $prototype = "static inline void trace_$tracepointname($tracepointargs)";
+       }
+}
+
 sub syscall_munge() {
        my $void = 0;
 
@@ -1882,6 +1901,9 @@ sub process_state3_function($$) {
        if ($prototype =~ /SYSCALL_DEFINE/) {
                syscall_munge();
        }
+       if ($prototype =~ /TRACE_EVENT/) {
+               tracepoint_munge($file);
+       }
        dump_function($prototype, $file);
        reset_state();
     }
index 409596eca124f7ada601417a59050eb12f55210a..0fae7da0529cac497a5337be4b6dd0e89cbf13d6 100755 (executable)
@@ -26,7 +26,7 @@
 # which will also be the location of that section after final link.
 # e.g.
 #
-#  .section ".text.sched"
+#  .section ".sched.text", "ax"
 #  .globl my_func
 #  my_func:
 #        [...]
@@ -39,7 +39,7 @@
 #        [...]
 #
 # Both relocation offsets for the mcounts in the above example will be
-# offset from .text.sched. If we make another file called tmp.s with:
+# offset from .sched.text. If we make another file called tmp.s with:
 #
 #  .section __mcount_loc
 #  .quad  my_func + 0x5
@@ -51,7 +51,7 @@
 # But this gets hard if my_func is not globl (a static function).
 # In such a case we have:
 #
-#  .section ".text.sched"
+#  .section ".sched.text", "ax"
 #  my_func:
 #        [...]
 #        call mcount  (offset: 0x5)
index bb244774e9d765ae10e41768f5dfd5c40f1f3069..d23c839038f00836cb96a51e53e27db8b8ec163c 100644 (file)
@@ -110,28 +110,8 @@ config SECURITY_ROOTPLUG
 
          See <http://www.linuxjournal.com/article.php?sid=6279> for
          more information about this module.
-         
-         If you are unsure how to answer this question, answer N.
-
-config SECURITY_DEFAULT_MMAP_MIN_ADDR
-        int "Low address space to protect from user allocation"
-        depends on SECURITY
-        default 0
-        help
-         This is the portion of low virtual memory which should be protected
-         from userspace allocation.  Keeping a user from writing to low pages
-         can help reduce the impact of kernel NULL pointer bugs.
-
-         For most ia64, ppc64 and x86 users with lots of address space
-         a value of 65536 is reasonable and should cause no problems.
-         On arm and other archs it should not be higher than 32768.
-         Programs which use vm86 functionality would either need additional
-         permissions from either the LSM or the capabilities module or have
-         this protection disabled.
-
-         This value can be changed after boot using the
-         /proc/sys/vm/mmap_min_addr tunable.
 
+         If you are unsure how to answer this question, answer N.
 
 source security/selinux/Kconfig
 source security/smack/Kconfig
index fa77021d9778ac1f32d7ec10e5322a0e6825e5c9..c67557cdaa857f9046d30cacb7f3ecc42196f9bb 100644 (file)
@@ -16,6 +16,9 @@ obj-$(CONFIG_SECURITYFS)              += inode.o
 # Must precede capability.o in order to stack properly.
 obj-$(CONFIG_SECURITY_SELINUX)         += selinux/built-in.o
 obj-$(CONFIG_SECURITY_SMACK)           += smack/built-in.o
+ifeq ($(CONFIG_AUDIT),y)
+obj-$(CONFIG_SECURITY_SMACK)           += lsm_audit.o
+endif
 obj-$(CONFIG_SECURITY_TOMOYO)          += tomoyo/built-in.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)                += root_plug.o
 obj-$(CONFIG_CGROUP_DEVICE)            += device_cgroup.o
index beac0258c2a8f3a0cbad52ec9adf12e019264626..48b7e0228fa38455ee6c2bf0cb37876e96c99afb 100644 (file)
 #include <linux/prctl.h>
 #include <linux/securebits.h>
 
+/*
+ * If a non-root user executes a setuid-root binary in
+ * !secure(SECURE_NOROOT) mode, then we raise capabilities.
+ * However if fE is also set, then the intent is for only
+ * the file capabilities to be applied, and the setuid-root
+ * bit is left on either to change the uid (plausible) or
+ * to get full privilege on a kernel without file capabilities
+ * support.  So in that case we do not raise capabilities.
+ *
+ * Warn if that happens, once per boot.
+ */
+static void warn_setuid_and_fcaps_mixed(char *fname)
+{
+       static int warned;
+       if (!warned) {
+               printk(KERN_INFO "warning: `%s' has both setuid-root and"
+                       " effective capabilities. Therefore not raising all"
+                       " capabilities.\n", fname);
+               warned = 1;
+       }
+}
+
 int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
 {
        NETLINK_CB(skb).eff_cap = current_cap();
@@ -463,6 +485,15 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
                return ret;
 
        if (!issecure(SECURE_NOROOT)) {
+               /*
+                * If the legacy file capability is set, then don't set privs
+                * for a setuid root binary run by a non-root user.  Do set it
+                * for a root user just to cause least surprise to an admin.
+                */
+               if (effective && new->uid != 0 && new->euid == 0) {
+                       warn_setuid_and_fcaps_mixed(bprm->filename);
+                       goto skip;
+               }
                /*
                 * To support inheritance of root-permissions and suid-root
                 * executables under compatibility mode, we override the
@@ -478,6 +509,7 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
                if (new->euid == 0)
                        effective = true;
        }
+skip:
 
        /* Don't let someone trace a set[ug]id/setpcap binary with the revised
         * credentials unless they have the appropriate permit
index f3b91bfbe4cb9483ea55e7e64c5c1c52b8c71d0d..f7496c6a022b7c2213f061c17b435bf0328085ed 100644 (file)
@@ -287,7 +287,7 @@ void securityfs_remove(struct dentry *dentry)
 {
        struct dentry *parent;
 
-       if (!dentry)
+       if (!dentry || IS_ERR(dentry))
                return;
 
        parent = dentry->d_parent;
index 1e082bb987beef1ca3322fd7409f57472bac60cc..ff513ff737f5c62861ff20e181567c195d126357 100644 (file)
@@ -22,18 +22,9 @@ static int ima_audit;
 static int __init ima_audit_setup(char *str)
 {
        unsigned long audit;
-       int rc, result = 0;
-       char *op = "ima_audit";
-       char *cause;
 
-       rc = strict_strtoul(str, 0, &audit);
-       if (rc || audit > 1)
-               result = 1;
-       else
-               ima_audit = audit;
-       cause = ima_audit ? "enabled" : "not_enabled";
-       integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
-                           op, cause, result, 0);
+       if (!strict_strtoul(str, 0, &audit))
+               ima_audit = audit ? 1 : 0;
        return 1;
 }
 __setup("ima_audit=", ima_audit_setup);
@@ -50,23 +41,14 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
 
        ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
        audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u ses=%u",
-                        current->pid, current->cred->uid,
+                        current->pid, current_cred()->uid,
                         audit_get_loginuid(current),
                         audit_get_sessionid(current));
        audit_log_task_context(ab);
-       switch (audit_msgno) {
-       case AUDIT_INTEGRITY_DATA:
-       case AUDIT_INTEGRITY_METADATA:
-       case AUDIT_INTEGRITY_PCR:
-       case AUDIT_INTEGRITY_STATUS:
-               audit_log_format(ab, " op=%s cause=%s", op, cause);
-               break;
-       case AUDIT_INTEGRITY_HASH:
-               audit_log_format(ab, " op=%s hash=%s", op, cause);
-               break;
-       default:
-               audit_log_format(ab, " op=%s", op);
-       }
+       audit_log_format(ab, " op=");
+       audit_log_string(ab, op);
+       audit_log_format(ab, " cause=");
+       audit_log_string(ab, cause);
        audit_log_format(ab, " comm=");
        audit_log_untrustedstring(ab, current->comm);
        if (fname) {
index 50d572b74caff78b157f9c713e6148d299b3c387..63003a63aaeedbc6fd6e6badaa3eaa5a705b67a8 100644 (file)
@@ -103,7 +103,7 @@ int ima_calc_template_hash(int template_len, void *template, char *digest)
        return rc;
 }
 
-static void ima_pcrread(int idx, u8 *pcr)
+static void __init ima_pcrread(int idx, u8 *pcr)
 {
        if (!ima_used_chip)
                return;
@@ -115,7 +115,7 @@ static void ima_pcrread(int idx, u8 *pcr)
 /*
  * Calculate the boot aggregate hash
  */
-int ima_calc_boot_aggregate(char *digest)
+int __init ima_calc_boot_aggregate(char *digest)
 {
        struct hash_desc desc;
        struct scatterlist sg;
index ffbe259700b10b54852cc5d4b29ae91a754230e4..6bfc7eaebfdabb88d7fbc9c5c61d7089d2c83f23 100644 (file)
@@ -15,6 +15,7 @@
  *     implemenents security file system for reporting
  *     current measurement list and IMA statistics
  */
+#include <linux/fcntl.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
 #include <linux/rculist.h>
@@ -84,8 +85,8 @@ static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
         * against concurrent list-extension
         */
        rcu_read_lock();
-       qe = list_entry(rcu_dereference(qe->later.next),
-                       struct ima_queue_entry, later);
+       qe = list_entry_rcu(qe->later.next,
+                           struct ima_queue_entry, later);
        rcu_read_unlock();
        (*pos)++;
 
@@ -283,6 +284,9 @@ static atomic_t policy_opencount = ATOMIC_INIT(1);
  */
 int ima_open_policy(struct inode * inode, struct file * filp)
 {
+       /* No point in being allowed to open it if you aren't going to write */
+       if (!(filp->f_flags & O_WRONLY))
+               return -EACCES;
        if (atomic_dec_and_test(&policy_opencount))
                return 0;
        return -EBUSY;
@@ -315,7 +319,7 @@ static struct file_operations ima_measure_policy_ops = {
        .release = ima_release_policy
 };
 
-int ima_fs_init(void)
+int __init ima_fs_init(void)
 {
        ima_dir = securityfs_create_dir("ima", NULL);
        if (IS_ERR(ima_dir))
@@ -349,7 +353,7 @@ int ima_fs_init(void)
                goto out;
 
        ima_policy = securityfs_create_file("policy",
-                                           S_IRUSR | S_IRGRP | S_IWUSR,
+                                           S_IWUSR,
                                            ima_dir, NULL,
                                            &ima_measure_policy_ops);
        if (IS_ERR(ima_policy))
index ec79f1ee992cb94c9362bc28f160633978c8c2d3..b8dd693f8790a62a4ae55b848bb8398cadbe3248 100644 (file)
@@ -196,7 +196,7 @@ static void init_once(void *foo)
        kref_set(&iint->refcount, 1);
 }
 
-void ima_iintcache_init(void)
+void __init ima_iintcache_init(void)
 {
        iint_cache =
            kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,
index 0b0bb8c978cc8575c6948a294fc08fa7efa14815..a40da7ae590021933bbb2d5982fc7a61494947ff 100644 (file)
@@ -38,7 +38,7 @@ int ima_used_chip;
  * a different value.) Violations add a zero entry to the measurement
  * list and extend the aggregate PCR value with ff...ff's.
  */
-static void ima_add_boot_aggregate(void)
+static void __init ima_add_boot_aggregate(void)
 {
        struct ima_template_entry *entry;
        const char *op = "add_boot_aggregate";
@@ -71,7 +71,7 @@ err_out:
                            audit_cause, result, 0);
 }
 
-int ima_init(void)
+int __init ima_init(void)
 {
        u8 pcr_i[IMA_DIGEST_SIZE];
        int rc;
index f4e7266f5aeec4f68de76ef040155153ae95ae1a..6f611874d10e9f7bbea81fab4fc537d68a711b75 100644 (file)
@@ -29,20 +29,8 @@ int ima_initialized;
 char *ima_hash = "sha1";
 static int __init hash_setup(char *str)
 {
-       const char *op = "hash_setup";
-       const char *hash = "sha1";
-       int result = 0;
-       int audit_info = 0;
-
-       if (strncmp(str, "md5", 3) == 0) {
-               hash = "md5";
-               ima_hash = str;
-       } else if (strncmp(str, "sha1", 4) != 0) {
-               hash = "invalid_hash_type";
-               result = 1;
-       }
-       integrity_audit_msg(AUDIT_INTEGRITY_HASH, NULL, NULL, op, hash,
-                           result, audit_info);
+       if (strncmp(str, "md5", 3) == 0)
+               ima_hash = "md5";
        return 1;
 }
 __setup("ima_hash=", hash_setup);
@@ -128,10 +116,6 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
 {
        int rc = 0;
 
-       if (IS_ERR(file)) {
-               pr_info("%s dentry_open failed\n", filename);
-               return rc;
-       }
        iint->opencount++;
        iint->readcount++;
 
@@ -141,6 +125,15 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
        return rc;
 }
 
+static void ima_update_counts(struct ima_iint_cache *iint, int mask)
+{
+       iint->opencount++;
+       if ((mask & MAY_WRITE) || (mask == 0))
+               iint->writecount++;
+       else if (mask & (MAY_READ | MAY_EXEC))
+               iint->readcount++;
+}
+
 /**
  * ima_path_check - based on policy, collect/store measurement.
  * @path: contains a pointer to the path to be measured
@@ -156,10 +149,10 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
  *     - Opening a file for read when already open for write,
  *       could result in a file measurement error.
  *
- * Return 0 on success, an error code on failure.
- * (Based on the results of appraise_measurement().)
+ * Always return 0 and audit dentry_open failures.
+ * (Return code will be based upon measurement appraisal.)
  */
-int ima_path_check(struct path *path, int mask)
+int ima_path_check(struct path *path, int mask, int update_counts)
 {
        struct inode *inode = path->dentry->d_inode;
        struct ima_iint_cache *iint;
@@ -173,11 +166,8 @@ int ima_path_check(struct path *path, int mask)
                return 0;
 
        mutex_lock(&iint->mutex);
-       iint->opencount++;
-       if ((mask & MAY_WRITE) || (mask == 0))
-               iint->writecount++;
-       else if (mask & (MAY_READ | MAY_EXEC))
-               iint->readcount++;
+       if (update_counts)
+               ima_update_counts(iint, mask);
 
        rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK);
        if (rc < 0)
@@ -196,7 +186,19 @@ int ima_path_check(struct path *path, int mask)
                struct dentry *dentry = dget(path->dentry);
                struct vfsmount *mnt = mntget(path->mnt);
 
-               file = dentry_open(dentry, mnt, O_RDONLY, current->cred);
+               file = dentry_open(dentry, mnt, O_RDONLY | O_LARGEFILE,
+                                  current_cred());
+               if (IS_ERR(file)) {
+                       int audit_info = 0;
+
+                       integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
+                                           dentry->d_name.name,
+                                           "add_measurement",
+                                           "dentry_open failed",
+                                           1, audit_info);
+                       file = NULL;
+                       goto out;
+               }
                rc = get_path_measurement(iint, file, dentry->d_name.name);
        }
 out:
@@ -206,6 +208,7 @@ out:
        kref_put(&iint->refcount, iint_free);
        return 0;
 }
+EXPORT_SYMBOL_GPL(ima_path_check);
 
 static int process_measurement(struct file *file, const unsigned char *filename,
                               int mask, int function)
@@ -234,7 +237,16 @@ out:
        return rc;
 }
 
-static void opencount_get(struct file *file)
+/*
+ * ima_opens_get - increment file counts
+ *
+ * - for IPC shm and shmat file.
+ * - for nfsd exported files.
+ *
+ * Increment the counts for these files to prevent unnecessary
+ * imbalance messages.
+ */
+void ima_counts_get(struct file *file)
 {
        struct inode *inode = file->f_dentry->d_inode;
        struct ima_iint_cache *iint;
@@ -246,8 +258,14 @@ static void opencount_get(struct file *file)
                return;
        mutex_lock(&iint->mutex);
        iint->opencount++;
+       if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
+               iint->readcount++;
+
+       if (file->f_mode & FMODE_WRITE)
+               iint->writecount++;
        mutex_unlock(&iint->mutex);
 }
+EXPORT_SYMBOL_GPL(ima_counts_get);
 
 /**
  * ima_file_mmap - based on policy, collect/store measurement.
@@ -272,18 +290,6 @@ int ima_file_mmap(struct file *file, unsigned long prot)
        return 0;
 }
 
-/*
- * ima_shm_check - IPC shm and shmat create/fput a file
- *
- * Maintain the opencount for these files to prevent unnecessary
- * imbalance messages.
- */
-void ima_shm_check(struct file *file)
-{
-       opencount_get(file);
-       return;
-}
-
 /**
  * ima_bprm_check - based on policy, collect/store measurement.
  * @bprm: contains the linux_binprm structure
index b5291ad5ef563b4a5707f0dc6b926fd2aafdf997..e1278399b34546a8ba5bbb4e8fdb90f9a8ec009f 100644 (file)
@@ -45,24 +45,30 @@ struct ima_measure_rule_entry {
        } lsm[MAX_LSM_RULES];
 };
 
-/* Without LSM specific knowledge, the default policy can only be
+/*
+ * Without LSM specific knowledge, the default policy can only be
  * written in terms of .action, .func, .mask, .fsmagic, and .uid
  */
+
+/*
+ * The minimum rule set to allow for full TCB coverage.  Measures all files
+ * opened or mmap for exec and everything read by root.  Dangerous because
+ * normal users can easily run the machine out of memory simply building
+ * and running executables.
+ */
 static struct ima_measure_rule_entry default_rules[] = {
-       {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,
-        .flags = IMA_FSMAGIC},
+       {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC},
-       {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,
-        .flags = IMA_FSMAGIC},
-       {.action = DONT_MEASURE,.fsmagic = 0xF97CFF8C,.flags = IMA_FSMAGIC},
+       {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC},
+       {.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC},
        {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC,
         .flags = IMA_FUNC | IMA_MASK},
        {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC,
         .flags = IMA_FUNC | IMA_MASK},
        {.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0,
-        .flags = IMA_FUNC | IMA_MASK | IMA_UID}
+        .flags = IMA_FUNC | IMA_MASK | IMA_UID},
 };
 
 static LIST_HEAD(measure_default_rules);
@@ -71,6 +77,14 @@ static struct list_head *ima_measure;
 
 static DEFINE_MUTEX(ima_measure_mutex);
 
+static bool ima_use_tcb __initdata;
+static int __init default_policy_setup(char *str)
+{
+       ima_use_tcb = 1;
+       return 1;
+}
+__setup("ima_tcb", default_policy_setup);
+
 /**
  * ima_match_rules - determine whether an inode matches the measure rule.
  * @rule: a pointer to a rule
@@ -96,7 +110,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule,
        if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid)
                return false;
        for (i = 0; i < MAX_LSM_RULES; i++) {
-               int rc;
+               int rc = 0;
                u32 osid, sid;
 
                if (!rule->lsm[i].rule)
@@ -109,7 +123,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule,
                        security_inode_getsecid(inode, &osid);
                        rc = security_filter_rule_match(osid,
                                                        rule->lsm[i].type,
-                                                       AUDIT_EQUAL,
+                                                       Audit_equal,
                                                        rule->lsm[i].rule,
                                                        NULL);
                        break;
@@ -119,7 +133,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule,
                        security_task_getsecid(tsk, &sid);
                        rc = security_filter_rule_match(sid,
                                                        rule->lsm[i].type,
-                                                       AUDIT_EQUAL,
+                                                       Audit_equal,
                                                        rule->lsm[i].rule,
                                                        NULL);
                default:
@@ -164,11 +178,17 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask)
  * ima_measure points to either the measure_default_rules or the
  * the new measure_policy_rules.
  */
-void ima_init_policy(void)
+void __init ima_init_policy(void)
 {
-       int i;
+       int i, entries;
+
+       /* if !ima_use_tcb set entries = 0 so we load NO default rules */
+       if (ima_use_tcb)
+               entries = ARRAY_SIZE(default_rules);
+       else
+               entries = 0;
 
-       for (i = 0; i < ARRAY_SIZE(default_rules); i++)
+       for (i = 0; i < entries; i++)
                list_add_tail(&default_rules[i].list, &measure_default_rules);
        ima_measure = &measure_default_rules;
 }
@@ -227,7 +247,7 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
 
        entry->lsm[lsm_rule].type = audit_type;
        result = security_filter_rule_init(entry->lsm[lsm_rule].type,
-                                          AUDIT_EQUAL, args,
+                                          Audit_equal, args,
                                           &entry->lsm[lsm_rule].rule);
        return result;
 }
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
new file mode 100644 (file)
index 0000000..94b8684
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * common LSM auditing functions
+ *
+ * Based on code written for SELinux by :
+ *                     Stephen Smalley, <sds@epoch.ncsc.mil>
+ *                     James Morris <jmorris@redhat.com>
+ * Author : Etienne Basset, <etienne.basset@ensta.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/types.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <net/sock.h>
+#include <linux/un.h>
+#include <net/af_unix.h>
+#include <linux/audit.h>
+#include <linux/ipv6.h>
+#include <linux/ip.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/dccp.h>
+#include <linux/sctp.h>
+#include <linux/lsm_audit.h>
+
+/**
+ * ipv4_skb_to_auditdata : fill auditdata from skb
+ * @skb : the skb
+ * @ad : the audit data to fill
+ * @proto : the layer 4 protocol
+ *
+ * return  0 on success
+ */
+int ipv4_skb_to_auditdata(struct sk_buff *skb,
+               struct common_audit_data *ad, u8 *proto)
+{
+       int ret = 0;
+       struct iphdr *ih;
+
+       ih = ip_hdr(skb);
+       if (ih == NULL)
+               return -EINVAL;
+
+       ad->u.net.v4info.saddr = ih->saddr;
+       ad->u.net.v4info.daddr = ih->daddr;
+
+       if (proto)
+               *proto = ih->protocol;
+       /* non initial fragment */
+       if (ntohs(ih->frag_off) & IP_OFFSET)
+               return 0;
+
+       switch (ih->protocol) {
+       case IPPROTO_TCP: {
+               struct tcphdr *th = tcp_hdr(skb);
+               if (th == NULL)
+                       break;
+
+               ad->u.net.sport = th->source;
+               ad->u.net.dport = th->dest;
+               break;
+       }
+       case IPPROTO_UDP: {
+               struct udphdr *uh = udp_hdr(skb);
+               if (uh == NULL)
+                       break;
+
+               ad->u.net.sport = uh->source;
+               ad->u.net.dport = uh->dest;
+               break;
+       }
+       case IPPROTO_DCCP: {
+               struct dccp_hdr *dh = dccp_hdr(skb);
+               if (dh == NULL)
+                       break;
+
+               ad->u.net.sport = dh->dccph_sport;
+               ad->u.net.dport = dh->dccph_dport;
+               break;
+       }
+       case IPPROTO_SCTP: {
+               struct sctphdr *sh = sctp_hdr(skb);
+               if (sh == NULL)
+                       break;
+               ad->u.net.sport = sh->source;
+               ad->u.net.dport = sh->dest;
+               break;
+       }
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * ipv6_skb_to_auditdata : fill auditdata from skb
+ * @skb : the skb
+ * @ad : the audit data to fill
+ * @proto : the layer 4 protocol
+ *
+ * return  0 on success
+ */
+int ipv6_skb_to_auditdata(struct sk_buff *skb,
+               struct common_audit_data *ad, u8 *proto)
+{
+       int offset, ret = 0;
+       struct ipv6hdr *ip6;
+       u8 nexthdr;
+
+       ip6 = ipv6_hdr(skb);
+       if (ip6 == NULL)
+               return -EINVAL;
+       ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
+       ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
+       ret = 0;
+       /* IPv6 can have several extension header before the Transport header
+        * skip them */
+       offset = skb_network_offset(skb);
+       offset += sizeof(*ip6);
+       nexthdr = ip6->nexthdr;
+       offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
+       if (offset < 0)
+               return 0;
+       if (proto)
+               *proto = nexthdr;
+       switch (nexthdr) {
+       case IPPROTO_TCP: {
+               struct tcphdr _tcph, *th;
+
+               th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
+               if (th == NULL)
+                       break;
+
+               ad->u.net.sport = th->source;
+               ad->u.net.dport = th->dest;
+               break;
+       }
+       case IPPROTO_UDP: {
+               struct udphdr _udph, *uh;
+
+               uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
+               if (uh == NULL)
+                       break;
+
+               ad->u.net.sport = uh->source;
+               ad->u.net.dport = uh->dest;
+               break;
+       }
+       case IPPROTO_DCCP: {
+               struct dccp_hdr _dccph, *dh;
+
+               dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
+               if (dh == NULL)
+                       break;
+
+               ad->u.net.sport = dh->dccph_sport;
+               ad->u.net.dport = dh->dccph_dport;
+               break;
+       }
+       case IPPROTO_SCTP: {
+               struct sctphdr _sctph, *sh;
+
+               sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
+               if (sh == NULL)
+                       break;
+               ad->u.net.sport = sh->source;
+               ad->u.net.dport = sh->dest;
+               break;
+       }
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+#endif
+
+
+static inline void print_ipv6_addr(struct audit_buffer *ab,
+                                  struct in6_addr *addr, __be16 port,
+                                  char *name1, char *name2)
+{
+       if (!ipv6_addr_any(addr))
+               audit_log_format(ab, " %s=%pI6", name1, addr);
+       if (port)
+               audit_log_format(ab, " %s=%d", name2, ntohs(port));
+}
+
+static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr,
+                                  __be16 port, char *name1, char *name2)
+{
+       if (addr)
+               audit_log_format(ab, " %s=%pI4", name1, &addr);
+       if (port)
+               audit_log_format(ab, " %s=%d", name2, ntohs(port));
+}
+
+/**
+ * dump_common_audit_data - helper to dump common audit data
+ * @a : common audit data
+ *
+ */
+static void dump_common_audit_data(struct audit_buffer *ab,
+                                  struct common_audit_data *a)
+{
+       struct inode *inode = NULL;
+       struct task_struct *tsk = current;
+
+       if (a->tsk)
+               tsk = a->tsk;
+       if (tsk && tsk->pid) {
+               audit_log_format(ab, " pid=%d comm=", tsk->pid);
+               audit_log_untrustedstring(ab, tsk->comm);
+       }
+
+       switch (a->type) {
+       case LSM_AUDIT_DATA_IPC:
+               audit_log_format(ab, " key=%d ", a->u.ipc_id);
+               break;
+       case LSM_AUDIT_DATA_CAP:
+               audit_log_format(ab, " capability=%d ", a->u.cap);
+               break;
+       case LSM_AUDIT_DATA_FS:
+               if (a->u.fs.path.dentry) {
+                       struct dentry *dentry = a->u.fs.path.dentry;
+                       if (a->u.fs.path.mnt) {
+                               audit_log_d_path(ab, "path=", &a->u.fs.path);
+                       } else {
+                               audit_log_format(ab, " name=");
+                               audit_log_untrustedstring(ab,
+                                                dentry->d_name.name);
+                       }
+                       inode = dentry->d_inode;
+               } else if (a->u.fs.inode) {
+                       struct dentry *dentry;
+                       inode = a->u.fs.inode;
+                       dentry = d_find_alias(inode);
+                       if (dentry) {
+                               audit_log_format(ab, " name=");
+                               audit_log_untrustedstring(ab,
+                                                dentry->d_name.name);
+                               dput(dentry);
+                       }
+               }
+               if (inode)
+                       audit_log_format(ab, " dev=%s ino=%lu",
+                                       inode->i_sb->s_id,
+                                       inode->i_ino);
+               break;
+       case LSM_AUDIT_DATA_TASK:
+               tsk = a->u.tsk;
+               if (tsk && tsk->pid) {
+                       audit_log_format(ab, " pid=%d comm=", tsk->pid);
+                       audit_log_untrustedstring(ab, tsk->comm);
+               }
+               break;
+       case LSM_AUDIT_DATA_NET:
+               if (a->u.net.sk) {
+                       struct sock *sk = a->u.net.sk;
+                       struct unix_sock *u;
+                       int len = 0;
+                       char *p = NULL;
+
+                       switch (sk->sk_family) {
+                       case AF_INET: {
+                               struct inet_sock *inet = inet_sk(sk);
+
+                               print_ipv4_addr(ab, inet->rcv_saddr,
+                                               inet->sport,
+                                               "laddr", "lport");
+                               print_ipv4_addr(ab, inet->daddr,
+                                               inet->dport,
+                                               "faddr", "fport");
+                               break;
+                       }
+                       case AF_INET6: {
+                               struct inet_sock *inet = inet_sk(sk);
+                               struct ipv6_pinfo *inet6 = inet6_sk(sk);
+
+                               print_ipv6_addr(ab, &inet6->rcv_saddr,
+                                               inet->sport,
+                                               "laddr", "lport");
+                               print_ipv6_addr(ab, &inet6->daddr,
+                                               inet->dport,
+                                               "faddr", "fport");
+                               break;
+                       }
+                       case AF_UNIX:
+                               u = unix_sk(sk);
+                               if (u->dentry) {
+                                       struct path path = {
+                                               .dentry = u->dentry,
+                                               .mnt = u->mnt
+                                       };
+                                       audit_log_d_path(ab, "path=", &path);
+                                       break;
+                               }
+                               if (!u->addr)
+                                       break;
+                               len = u->addr->len-sizeof(short);
+                               p = &u->addr->name->sun_path[0];
+                               audit_log_format(ab, " path=");
+                               if (*p)
+                                       audit_log_untrustedstring(ab, p);
+                               else
+                                       audit_log_n_hex(ab, p, len);
+                               break;
+                       }
+               }
+
+               switch (a->u.net.family) {
+               case AF_INET:
+                       print_ipv4_addr(ab, a->u.net.v4info.saddr,
+                                       a->u.net.sport,
+                                       "saddr", "src");
+                       print_ipv4_addr(ab, a->u.net.v4info.daddr,
+                                       a->u.net.dport,
+                                       "daddr", "dest");
+                       break;
+               case AF_INET6:
+                       print_ipv6_addr(ab, &a->u.net.v6info.saddr,
+                                       a->u.net.sport,
+                                       "saddr", "src");
+                       print_ipv6_addr(ab, &a->u.net.v6info.daddr,
+                                       a->u.net.dport,
+                                       "daddr", "dest");
+                       break;
+               }
+               if (a->u.net.netif > 0) {
+                       struct net_device *dev;
+
+                       /* NOTE: we always use init's namespace */
+                       dev = dev_get_by_index(&init_net, a->u.net.netif);
+                       if (dev) {
+                               audit_log_format(ab, " netif=%s", dev->name);
+                               dev_put(dev);
+                       }
+               }
+               break;
+#ifdef CONFIG_KEYS
+       case LSM_AUDIT_DATA_KEY:
+               audit_log_format(ab, " key_serial=%u", a->u.key_struct.key);
+               if (a->u.key_struct.key_desc) {
+                       audit_log_format(ab, " key_desc=");
+                       audit_log_untrustedstring(ab, a->u.key_struct.key_desc);
+               }
+               break;
+#endif
+       } /* switch (a->type) */
+}
+
+/**
+ * common_lsm_audit - generic LSM auditing function
+ * @a:  auxiliary audit data
+ *
+ * setup the audit buffer for common security information
+ * uses callback to print LSM specific information
+ */
+void common_lsm_audit(struct common_audit_data *a)
+{
+       struct audit_buffer *ab;
+
+       if (a == NULL)
+               return;
+       /* we use GFP_ATOMIC so we won't sleep */
+       ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC);
+
+       if (ab == NULL)
+               return;
+
+       if (a->lsm_pre_audit)
+               a->lsm_pre_audit(ab, a);
+
+       dump_common_audit_data(ab, a);
+
+       if (a->lsm_post_audit)
+               a->lsm_post_audit(ab, a);
+
+       audit_log_end(ab);
+}
index 40fb4f15e27b6d360e1634c4d0f795e0edf621c1..2f7ffa67c4d2db7069f6c2e9b141eb544c409d25 100644 (file)
@@ -71,18 +71,6 @@ static int rootplug_bprm_check_security (struct linux_binprm *bprm)
 }
 
 static struct security_operations rootplug_security_ops = {
-       /* Use the capability functions for some of the hooks */
-       .ptrace_may_access =            cap_ptrace_may_access,
-       .ptrace_traceme =               cap_ptrace_traceme,
-       .capget =                       cap_capget,
-       .capset =                       cap_capset,
-       .capable =                      cap_capable,
-
-       .bprm_set_creds =               cap_bprm_set_creds,
-
-       .task_fix_setuid =              cap_task_fix_setuid,
-       .task_prctl =                   cap_task_prctl,
-
        .bprm_check_security =          rootplug_bprm_check_security,
 };
 
index 5284255c5cdff9869ac4086c3a8976a4d9ad0a1a..dc7674fbfc7a4a6fcfb132bc974f2c9480b90922 100644 (file)
@@ -26,9 +26,6 @@ extern void security_fixup_ops(struct security_operations *ops);
 
 struct security_operations *security_ops;      /* Initialized to NULL */
 
-/* amount of vm to protect from userspace access */
-unsigned long mmap_min_addr = CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR;
-
 static inline int verify(struct security_operations *ops)
 {
        /* verify the security_operations structure exists */
index 7f9b5fac87793a19faf3d310a4e04f8a158bb476..b2ab608598325bcea26430f6ebd1eac30a67ad61 100644 (file)
@@ -927,7 +927,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
        if (denied) {
                if (flags & AVC_STRICT)
                        rc = -EACCES;
-               else if (!selinux_enforcing || security_permissive_sid(ssid))
+               else if (!selinux_enforcing || (avd->flags & AVD_FLAGS_PERMISSIVE))
                        avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,
                                        tsid, tclass, avd->seqno);
                else
index 2fcad7c33eafd43a5e67beef49aea5f7cd020a89..195906bce2663f09e4fb65c4e39edb2cd20d0d33 100644 (file)
@@ -1980,10 +1980,6 @@ static int selinux_sysctl(ctl_table *table, int op)
        u32 tsid, sid;
        int rc;
 
-       rc = secondary_ops->sysctl(table, op);
-       if (rc)
-               return rc;
-
        sid = current_sid();
 
        rc = selinux_sysctl_get_sid(table, (op == 0001) ?
@@ -2375,10 +2371,8 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
 {
        const struct task_security_struct *tsec = current_security();
        struct itimerval itimer;
-       struct sighand_struct *psig;
        u32 osid, sid;
        int rc, i;
-       unsigned long flags;
 
        osid = tsec->osid;
        sid = tsec->sid;
@@ -2398,22 +2392,20 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
                memset(&itimer, 0, sizeof itimer);
                for (i = 0; i < 3; i++)
                        do_setitimer(i, &itimer, NULL);
-               flush_signals(current);
                spin_lock_irq(&current->sighand->siglock);
-               flush_signal_handlers(current, 1);
-               sigemptyset(&current->blocked);
-               recalc_sigpending();
+               if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
+                       __flush_signals(current);
+                       flush_signal_handlers(current, 1);
+                       sigemptyset(&current->blocked);
+               }
                spin_unlock_irq(&current->sighand->siglock);
        }
 
        /* Wake up the parent if it is waiting so that it can recheck
         * wait permission to the new task SID. */
-       read_lock_irq(&tasklist_lock);
-       psig = current->parent->sighand;
-       spin_lock_irqsave(&psig->siglock, flags);
-       wake_up_interruptible(&current->parent->signal->wait_chldexit);
-       spin_unlock_irqrestore(&psig->siglock, flags);
-       read_unlock_irq(&tasklist_lock);
+       read_lock(&tasklist_lock);
+       wake_up_interruptible(&current->real_parent->signal->wait_chldexit);
+       read_unlock(&tasklist_lock);
 }
 
 /* superblock security operations */
index 5c3434f7626fdd5cbe81ff0120ad3f092713fd95..ca835795a8b322e7e4398d065d2eb0976741e2ad 100644 (file)
@@ -8,14 +8,13 @@
 #ifndef _SELINUX_SECURITY_H_
 #define _SELINUX_SECURITY_H_
 
+#include <linux/magic.h>
 #include "flask.h"
 
 #define SECSID_NULL                    0x00000000 /* unspecified SID */
 #define SECSID_WILD                    0xffffffff /* wildcard SID */
 #define SECCLASS_NULL                  0x0000 /* no class */
 
-#define SELINUX_MAGIC 0xf97cff8c
-
 /* Identify specific policy version changes */
 #define POLICYDB_VERSION_BASE          15
 #define POLICYDB_VERSION_BOOL          16
@@ -91,9 +90,11 @@ struct av_decision {
        u32 auditallow;
        u32 auditdeny;
        u32 seqno;
+       u32 flags;
 };
 
-int security_permissive_sid(u32 sid);
+/* definitions of av_decision.flags */
+#define AVD_FLAGS_PERMISSIVE   0x0001
 
 int security_compute_av(u32 ssid, u32 tsid,
        u16 tclass, u32 requested,
index c6875fd3b9d61445009f22d3ea8b91037b864d25..dd7cc6de77f9e3a47118b6e8dffca3538b36adb3 100644 (file)
@@ -112,6 +112,8 @@ static struct nlmsg_perm nlmsg_audit_perms[] =
        { AUDIT_DEL_RULE,       NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
        { AUDIT_USER,           NETLINK_AUDIT_SOCKET__NLMSG_RELAY    },
        { AUDIT_SIGNAL_INFO,    NETLINK_AUDIT_SOCKET__NLMSG_READ     },
+       { AUDIT_TRIM,           NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+       { AUDIT_MAKE_EQUIV,     NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
        { AUDIT_TTY_GET,        NETLINK_AUDIT_SOCKET__NLMSG_READ     },
        { AUDIT_TTY_SET,        NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT   },
 };
index 2d5136ec3d5451c945f89e59b2f9ea4433bfa6a4..b4fc506e7a87c8aa69a71ccc1a9c1b6c55c00ce8 100644 (file)
@@ -527,10 +527,10 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
                goto out2;
 
        length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
-                         "%x %x %x %x %u",
+                         "%x %x %x %x %u %x",
                          avd.allowed, 0xffffffff,
                          avd.auditallow, avd.auditdeny,
-                         avd.seqno);
+                         avd.seqno, avd.flags);
 out2:
        kfree(tcon);
 out:
@@ -803,10 +803,6 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
                goto out;
        }
 
-       if (count > PAGE_SIZE) {
-               ret = -EINVAL;
-               goto out;
-       }
        page = (char *)get_zeroed_page(GFP_KERNEL);
        if (!page) {
                ret = -ENOMEM;
index deeec6c013aef6dee9d664e3fe46b0a892d9f27e..500e6f78e1159e1d568355ce74a113b4b49859c1 100644 (file)
@@ -410,6 +410,7 @@ static int context_struct_compute_av(struct context *scontext,
        avd->auditallow = 0;
        avd->auditdeny = 0xffffffff;
        avd->seqno = latest_granting;
+       avd->flags = 0;
 
        /*
         * Check for all the invalid cases.
@@ -528,31 +529,6 @@ inval_class:
        return 0;
 }
 
-/*
- * Given a sid find if the type has the permissive flag set
- */
-int security_permissive_sid(u32 sid)
-{
-       struct context *context;
-       u32 type;
-       int rc;
-
-       read_lock(&policy_rwlock);
-
-       context = sidtab_search(&sidtab, sid);
-       BUG_ON(!context);
-
-       type = context->type;
-       /*
-        * we are intentionally using type here, not type-1, the 0th bit may
-        * someday indicate that we are globally setting permissive in policy.
-        */
-       rc = ebitmap_get_bit(&policydb.permissive_map, type);
-
-       read_unlock(&policy_rwlock);
-       return rc;
-}
-
 static int security_validtrans_handle_fail(struct context *ocontext,
                                           struct context *ncontext,
                                           struct context *tcontext,
@@ -767,6 +743,10 @@ int security_compute_av(u32 ssid,
 
        rc = context_struct_compute_av(scontext, tcontext, tclass,
                                       requested, avd);
+
+       /* permissive domain? */
+       if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
+           avd->flags |= AVD_FLAGS_PERMISSIVE;
 out:
        read_unlock(&policy_rwlock);
        return rc;
index 42ef313f98560451b2b45d563d1f5e26e23ca795..243bec175be050f930189a25d4a4bb6d5dc85ef3 100644 (file)
@@ -20,6 +20,7 @@
 #include <net/netlabel.h>
 #include <linux/list.h>
 #include <linux/rculist.h>
+#include <linux/lsm_audit.h>
 
 /*
  * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
@@ -178,6 +179,20 @@ struct smack_known {
 #define MAY_READWRITE  (MAY_READ | MAY_WRITE)
 #define MAY_NOT                0
 
+/*
+ * Number of access types used by Smack (rwxa)
+ */
+#define SMK_NUM_ACCESS_TYPE 4
+
+/*
+ * Smack audit data; is empty if CONFIG_AUDIT not set
+ * to save some stack
+ */
+struct smk_audit_info {
+#ifdef CONFIG_AUDIT
+       struct common_audit_data a;
+#endif
+};
 /*
  * These functions are in smack_lsm.c
  */
@@ -186,8 +201,8 @@ struct inode_smack *new_inode_smack(char *);
 /*
  * These functions are in smack_access.c
  */
-int smk_access(char *, char *, int);
-int smk_curacc(char *, u32);
+int smk_access(char *, char *, int, struct smk_audit_info *);
+int smk_curacc(char *, u32, struct smk_audit_info *);
 int smack_to_cipso(const char *, struct smack_cipso *);
 void smack_from_cipso(u32, char *, char *);
 char *smack_from_secid(const u32);
@@ -237,4 +252,93 @@ static inline char *smk_of_inode(const struct inode *isp)
        return sip->smk_inode;
 }
 
+/*
+ * logging functions
+ */
+#define SMACK_AUDIT_DENIED 0x1
+#define SMACK_AUDIT_ACCEPT 0x2
+extern int log_policy;
+
+void smack_log(char *subject_label, char *object_label,
+               int request,
+               int result, struct smk_audit_info *auditdata);
+
+#ifdef CONFIG_AUDIT
+
+/*
+ * some inline functions to set up audit data
+ * they do nothing if CONFIG_AUDIT is not set
+ *
+ */
+static inline void smk_ad_init(struct smk_audit_info *a, const char *func,
+                              char type)
+{
+       memset(a, 0, sizeof(*a));
+       a->a.type = type;
+       a->a.function = func;
+}
+
+static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a,
+                                        struct task_struct *t)
+{
+       a->a.u.tsk = t;
+}
+static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a,
+                                                   struct dentry *d)
+{
+       a->a.u.fs.path.dentry = d;
+}
+static inline void smk_ad_setfield_u_fs_path_mnt(struct smk_audit_info *a,
+                                                struct vfsmount *m)
+{
+       a->a.u.fs.path.mnt = m;
+}
+static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a,
+                                             struct inode *i)
+{
+       a->a.u.fs.inode = i;
+}
+static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a,
+                                            struct path p)
+{
+       a->a.u.fs.path = p;
+}
+static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a,
+                                           struct sock *sk)
+{
+       a->a.u.net.sk = sk;
+}
+
+#else /* no AUDIT */
+
+static inline void smk_ad_init(struct smk_audit_info *a, const char *func,
+                              char type)
+{
+}
+static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a,
+                                        struct task_struct *t)
+{
+}
+static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a,
+                                                   struct dentry *d)
+{
+}
+static inline void smk_ad_setfield_u_fs_path_mnt(struct smk_audit_info *a,
+                                                struct vfsmount *m)
+{
+}
+static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a,
+                                             struct inode *i)
+{
+}
+static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a,
+                                            struct path p)
+{
+}
+static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a,
+                                           struct sock *sk)
+{
+}
+#endif
+
 #endif  /* _SECURITY_SMACK_H */
index ac0a2707f6d41583e9e325819ab2265483320853..513dc1aa16dd1ff5594745b463dd67118648705a 100644 (file)
@@ -59,11 +59,18 @@ LIST_HEAD(smack_known_list);
  */
 static u32 smack_next_secid = 10;
 
+/*
+ * what events do we log
+ * can be overwritten at run-time by /smack/logging
+ */
+int log_policy = SMACK_AUDIT_DENIED;
+
 /**
  * smk_access - determine if a subject has a specific access to an object
  * @subject_label: a pointer to the subject's Smack label
  * @object_label: a pointer to the object's Smack label
  * @request: the access requested, in "MAY" format
+ * @a : a pointer to the audit data
  *
  * This function looks up the subject/object pair in the
  * access rule list and returns 0 if the access is permitted,
@@ -78,10 +85,12 @@ static u32 smack_next_secid = 10;
  * will be on the list, so checking the pointers may be a worthwhile
  * optimization.
  */
-int smk_access(char *subject_label, char *object_label, int request)
+int smk_access(char *subject_label, char *object_label, int request,
+              struct smk_audit_info *a)
 {
        u32 may = MAY_NOT;
        struct smack_rule *srp;
+       int rc = 0;
 
        /*
         * Hardcoded comparisons.
@@ -89,8 +98,10 @@ int smk_access(char *subject_label, char *object_label, int request)
         * A star subject can't access any object.
         */
        if (subject_label == smack_known_star.smk_known ||
-           strcmp(subject_label, smack_known_star.smk_known) == 0)
-               return -EACCES;
+           strcmp(subject_label, smack_known_star.smk_known) == 0) {
+               rc = -EACCES;
+               goto out_audit;
+       }
        /*
         * An internet object can be accessed by any subject.
         * Tasks cannot be assigned the internet label.
@@ -100,20 +111,20 @@ int smk_access(char *subject_label, char *object_label, int request)
            subject_label == smack_known_web.smk_known ||
            strcmp(object_label, smack_known_web.smk_known) == 0 ||
            strcmp(subject_label, smack_known_web.smk_known) == 0)
-               return 0;
+               goto out_audit;
        /*
         * A star object can be accessed by any subject.
         */
        if (object_label == smack_known_star.smk_known ||
            strcmp(object_label, smack_known_star.smk_known) == 0)
-               return 0;
+               goto out_audit;
        /*
         * An object can be accessed in any way by a subject
         * with the same label.
         */
        if (subject_label == object_label ||
            strcmp(subject_label, object_label) == 0)
-               return 0;
+               goto out_audit;
        /*
         * A hat subject can read any object.
         * A floor object can be read by any subject.
@@ -121,10 +132,10 @@ int smk_access(char *subject_label, char *object_label, int request)
        if ((request & MAY_ANYREAD) == request) {
                if (object_label == smack_known_floor.smk_known ||
                    strcmp(object_label, smack_known_floor.smk_known) == 0)
-                       return 0;
+                       goto out_audit;
                if (subject_label == smack_known_hat.smk_known ||
                    strcmp(subject_label, smack_known_hat.smk_known) == 0)
-                       return 0;
+                       goto out_audit;
        }
        /*
         * Beyond here an explicit relationship is required.
@@ -148,28 +159,36 @@ int smk_access(char *subject_label, char *object_label, int request)
         * This is a bit map operation.
         */
        if ((request & may) == request)
-               return 0;
-
-       return -EACCES;
+               goto out_audit;
+
+       rc = -EACCES;
+out_audit:
+#ifdef CONFIG_AUDIT
+       if (a)
+               smack_log(subject_label, object_label, request, rc, a);
+#endif
+       return rc;
 }
 
 /**
  * smk_curacc - determine if current has a specific access to an object
  * @obj_label: a pointer to the object's Smack label
  * @mode: the access requested, in "MAY" format
+ * @a : common audit data
  *
  * This function checks the current subject label/object label pair
  * in the access rule list and returns 0 if the access is permitted,
  * non zero otherwise. It allows that current may have the capability
  * to override the rules.
  */
-int smk_curacc(char *obj_label, u32 mode)
+int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
 {
        int rc;
+       char *sp = current_security();
 
-       rc = smk_access(current_security(), obj_label, mode);
+       rc = smk_access(sp, obj_label, mode, NULL);
        if (rc == 0)
-               return 0;
+               goto out_audit;
 
        /*
         * Return if a specific label has been designated as the
@@ -177,14 +196,105 @@ int smk_curacc(char *obj_label, u32 mode)
         * have that label.
         */
        if (smack_onlycap != NULL && smack_onlycap != current->cred->security)
-               return rc;
+               goto out_audit;
 
        if (capable(CAP_MAC_OVERRIDE))
                return 0;
 
+out_audit:
+#ifdef CONFIG_AUDIT
+       if (a)
+               smack_log(sp, obj_label, mode, rc, a);
+#endif
        return rc;
 }
 
+#ifdef CONFIG_AUDIT
+/**
+ * smack_str_from_perm : helper to transalate an int to a
+ * readable string
+ * @string : the string to fill
+ * @access : the int
+ *
+ */
+static inline void smack_str_from_perm(char *string, int access)
+{
+       int i = 0;
+       if (access & MAY_READ)
+               string[i++] = 'r';
+       if (access & MAY_WRITE)
+               string[i++] = 'w';
+       if (access & MAY_EXEC)
+               string[i++] = 'x';
+       if (access & MAY_APPEND)
+               string[i++] = 'a';
+       string[i] = '\0';
+}
+/**
+ * smack_log_callback - SMACK specific information
+ * will be called by generic audit code
+ * @ab : the audit_buffer
+ * @a  : audit_data
+ *
+ */
+static void smack_log_callback(struct audit_buffer *ab, void *a)
+{
+       struct common_audit_data *ad = a;
+       struct smack_audit_data *sad = &ad->lsm_priv.smack_audit_data;
+       audit_log_format(ab, "lsm=SMACK fn=%s action=%s", ad->function,
+                        sad->result ? "denied" : "granted");
+       audit_log_format(ab, " subject=");
+       audit_log_untrustedstring(ab, sad->subject);
+       audit_log_format(ab, " object=");
+       audit_log_untrustedstring(ab, sad->object);
+       audit_log_format(ab, " requested=%s", sad->request);
+}
+
+/**
+ *  smack_log - Audit the granting or denial of permissions.
+ *  @subject_label : smack label of the requester
+ *  @object_label  : smack label of the object being accessed
+ *  @request: requested permissions
+ *  @result: result from smk_access
+ *  @a:  auxiliary audit data
+ *
+ * Audit the granting or denial of permissions in accordance
+ * with the policy.
+ */
+void smack_log(char *subject_label, char *object_label, int request,
+              int result, struct smk_audit_info *ad)
+{
+       char request_buffer[SMK_NUM_ACCESS_TYPE + 1];
+       struct smack_audit_data *sad;
+       struct common_audit_data *a = &ad->a;
+
+       /* check if we have to log the current event */
+       if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
+               return;
+       if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
+               return;
+
+       if (a->function == NULL)
+               a->function = "unknown";
+
+       /* end preparing the audit data */
+       sad = &a->lsm_priv.smack_audit_data;
+       smack_str_from_perm(request_buffer, request);
+       sad->subject = subject_label;
+       sad->object  = object_label;
+       sad->request = request_buffer;
+       sad->result  = result;
+       a->lsm_pre_audit = smack_log_callback;
+
+       common_lsm_audit(a);
+}
+#else /* #ifdef CONFIG_AUDIT */
+void smack_log(char *subject_label, char *object_label, int request,
+               int result, struct smk_audit_info *ad)
+{
+}
+#endif
+
 static DEFINE_MUTEX(smack_known_lock);
 
 /**
@@ -209,7 +319,8 @@ struct smack_known *smk_import_entry(const char *string, int len)
                if (found)
                        smack[i] = '\0';
                else if (i >= len || string[i] > '~' || string[i] <= ' ' ||
-                        string[i] == '/') {
+                        string[i] == '/' || string[i] == '"' ||
+                        string[i] == '\\' || string[i] == '\'') {
                        smack[i] = '\0';
                        found = 1;
                } else
index 98b3195347ab46d84749920de3b6b45df134de5f..0023182078c726797de5ccab784a1922eba17859 100644 (file)
@@ -30,7 +30,6 @@
 #include <net/netlabel.h>
 #include <net/cipso_ipv4.h>
 #include <linux/audit.h>
-
 #include "smack.h"
 
 #define task_security(task)    (task_cred_xxx((task), security))
@@ -103,14 +102,24 @@ struct inode_smack *new_inode_smack(char *smack)
 static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode)
 {
        int rc;
+       struct smk_audit_info ad;
+       char *sp, *tsp;
 
        rc = cap_ptrace_may_access(ctp, mode);
        if (rc != 0)
                return rc;
 
-       rc = smk_access(current_security(), task_security(ctp), MAY_READWRITE);
+       sp = current_security();
+       tsp = task_security(ctp);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
+       smk_ad_setfield_u_tsk(&ad, ctp);
+
+       /* we won't log here, because rc can be overriden */
+       rc = smk_access(sp, tsp, MAY_READWRITE, NULL);
        if (rc != 0 && capable(CAP_MAC_OVERRIDE))
-               return 0;
+               rc = 0;
+
+       smack_log(sp, tsp, MAY_READWRITE, rc, &ad);
        return rc;
 }
 
@@ -125,14 +134,24 @@ static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode)
 static int smack_ptrace_traceme(struct task_struct *ptp)
 {
        int rc;
+       struct smk_audit_info ad;
+       char *sp, *tsp;
 
        rc = cap_ptrace_traceme(ptp);
        if (rc != 0)
                return rc;
 
-       rc = smk_access(task_security(ptp), current_security(), MAY_READWRITE);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
+       smk_ad_setfield_u_tsk(&ad, ptp);
+
+       sp = current_security();
+       tsp = task_security(ptp);
+       /* we won't log here, because rc can be overriden */
+       rc = smk_access(tsp, sp, MAY_READWRITE, NULL);
        if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE))
-               return 0;
+               rc = 0;
+
+       smack_log(tsp, sp, MAY_READWRITE, rc, &ad);
        return rc;
 }
 
@@ -327,8 +346,14 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
 static int smack_sb_statfs(struct dentry *dentry)
 {
        struct superblock_smack *sbp = dentry->d_sb->s_security;
+       int rc;
+       struct smk_audit_info ad;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
-       return smk_curacc(sbp->smk_floor, MAY_READ);
+       rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad);
+       return rc;
 }
 
 /**
@@ -346,8 +371,12 @@ static int smack_sb_mount(char *dev_name, struct path *path,
                          char *type, unsigned long flags, void *data)
 {
        struct superblock_smack *sbp = path->mnt->mnt_sb->s_security;
+       struct smk_audit_info ad;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path(&ad, *path);
 
-       return smk_curacc(sbp->smk_floor, MAY_WRITE);
+       return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
 }
 
 /**
@@ -361,10 +390,14 @@ static int smack_sb_mount(char *dev_name, struct path *path,
 static int smack_sb_umount(struct vfsmount *mnt, int flags)
 {
        struct superblock_smack *sbp;
+       struct smk_audit_info ad;
 
-       sbp = mnt->mnt_sb->s_security;
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path_dentry(&ad, mnt->mnt_mountpoint);
+       smk_ad_setfield_u_fs_path_mnt(&ad, mnt);
 
-       return smk_curacc(sbp->smk_floor, MAY_WRITE);
+       sbp = mnt->mnt_sb->s_security;
+       return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
 }
 
 /*
@@ -441,15 +474,20 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
 static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
                            struct dentry *new_dentry)
 {
-       int rc;
        char *isp;
+       struct smk_audit_info ad;
+       int rc;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
 
        isp = smk_of_inode(old_dentry->d_inode);
-       rc = smk_curacc(isp, MAY_WRITE);
+       rc = smk_curacc(isp, MAY_WRITE, &ad);
 
        if (rc == 0 && new_dentry->d_inode != NULL) {
                isp = smk_of_inode(new_dentry->d_inode);
-               rc = smk_curacc(isp, MAY_WRITE);
+               smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry);
+               rc = smk_curacc(isp, MAY_WRITE, &ad);
        }
 
        return rc;
@@ -466,18 +504,24 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
 static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
 {
        struct inode *ip = dentry->d_inode;
+       struct smk_audit_info ad;
        int rc;
 
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
+
        /*
         * You need write access to the thing you're unlinking
         */
-       rc = smk_curacc(smk_of_inode(ip), MAY_WRITE);
-       if (rc == 0)
+       rc = smk_curacc(smk_of_inode(ip), MAY_WRITE, &ad);
+       if (rc == 0) {
                /*
                 * You also need write access to the containing directory
                 */
-               rc = smk_curacc(smk_of_inode(dir), MAY_WRITE);
-
+               smk_ad_setfield_u_fs_path_dentry(&ad, NULL);
+               smk_ad_setfield_u_fs_inode(&ad, dir);
+               rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
+       }
        return rc;
 }
 
@@ -491,17 +535,24 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
  */
 static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
 {
+       struct smk_audit_info ad;
        int rc;
 
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
+
        /*
         * You need write access to the thing you're removing
         */
-       rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
-       if (rc == 0)
+       rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+       if (rc == 0) {
                /*
                 * You also need write access to the containing directory
                 */
-               rc = smk_curacc(smk_of_inode(dir), MAY_WRITE);
+               smk_ad_setfield_u_fs_path_dentry(&ad, NULL);
+               smk_ad_setfield_u_fs_inode(&ad, dir);
+               rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
+       }
 
        return rc;
 }
@@ -525,15 +576,19 @@ static int smack_inode_rename(struct inode *old_inode,
 {
        int rc;
        char *isp;
+       struct smk_audit_info ad;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
 
        isp = smk_of_inode(old_dentry->d_inode);
-       rc = smk_curacc(isp, MAY_READWRITE);
+       rc = smk_curacc(isp, MAY_READWRITE, &ad);
 
        if (rc == 0 && new_dentry->d_inode != NULL) {
                isp = smk_of_inode(new_dentry->d_inode);
-               rc = smk_curacc(isp, MAY_READWRITE);
+               smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry);
+               rc = smk_curacc(isp, MAY_READWRITE, &ad);
        }
-
        return rc;
 }
 
@@ -548,13 +603,15 @@ static int smack_inode_rename(struct inode *old_inode,
  */
 static int smack_inode_permission(struct inode *inode, int mask)
 {
+       struct smk_audit_info ad;
        /*
         * No permission to check. Existence test. Yup, it's there.
         */
        if (mask == 0)
                return 0;
-
-       return smk_curacc(smk_of_inode(inode), mask);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_inode(&ad, inode);
+       return smk_curacc(smk_of_inode(inode), mask, &ad);
 }
 
 /**
@@ -566,13 +623,16 @@ static int smack_inode_permission(struct inode *inode, int mask)
  */
 static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 {
+       struct smk_audit_info ad;
        /*
         * Need to allow for clearing the setuid bit.
         */
        if (iattr->ia_valid & ATTR_FORCE)
                return 0;
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
-       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
+       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
 }
 
 /**
@@ -584,7 +644,12 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
  */
 static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
 {
-       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
+       struct smk_audit_info ad;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
+       smk_ad_setfield_u_fs_path_mnt(&ad, mnt);
+       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
 }
 
 /**
@@ -602,6 +667,7 @@ static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
 static int smack_inode_setxattr(struct dentry *dentry, const char *name,
                                const void *value, size_t size, int flags)
 {
+       struct smk_audit_info ad;
        int rc = 0;
 
        if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
@@ -619,8 +685,11 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
        } else
                rc = cap_inode_setxattr(dentry, name, value, size, flags);
 
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
+
        if (rc == 0)
-               rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
+               rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
 
        return rc;
 }
@@ -672,7 +741,12 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
  */
 static int smack_inode_getxattr(struct dentry *dentry, const char *name)
 {
-       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
+       struct smk_audit_info ad;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
+
+       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
 }
 
 /*
@@ -686,6 +760,7 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)
  */
 static int smack_inode_removexattr(struct dentry *dentry, const char *name)
 {
+       struct smk_audit_info ad;
        int rc = 0;
 
        if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
@@ -696,8 +771,10 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
        } else
                rc = cap_inode_removexattr(dentry, name);
 
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
        if (rc == 0)
-               rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
+               rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
 
        return rc;
 }
@@ -856,12 +933,16 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
                            unsigned long arg)
 {
        int rc = 0;
+       struct smk_audit_info ad;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path(&ad, file->f_path);
 
        if (_IOC_DIR(cmd) & _IOC_WRITE)
-               rc = smk_curacc(file->f_security, MAY_WRITE);
+               rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
 
        if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ))
-               rc = smk_curacc(file->f_security, MAY_READ);
+               rc = smk_curacc(file->f_security, MAY_READ, &ad);
 
        return rc;
 }
@@ -875,7 +956,11 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
  */
 static int smack_file_lock(struct file *file, unsigned int cmd)
 {
-       return smk_curacc(file->f_security, MAY_WRITE);
+       struct smk_audit_info ad;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path_dentry(&ad, file->f_path.dentry);
+       return smk_curacc(file->f_security, MAY_WRITE, &ad);
 }
 
 /**
@@ -889,8 +974,12 @@ static int smack_file_lock(struct file *file, unsigned int cmd)
 static int smack_file_fcntl(struct file *file, unsigned int cmd,
                            unsigned long arg)
 {
+       struct smk_audit_info ad;
        int rc;
 
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_setfield_u_fs_path(&ad, file->f_path);
+
        switch (cmd) {
        case F_DUPFD:
        case F_GETFD:
@@ -898,7 +987,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
        case F_GETLK:
        case F_GETOWN:
        case F_GETSIG:
-               rc = smk_curacc(file->f_security, MAY_READ);
+               rc = smk_curacc(file->f_security, MAY_READ, &ad);
                break;
        case F_SETFD:
        case F_SETFL:
@@ -906,10 +995,10 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
        case F_SETLKW:
        case F_SETOWN:
        case F_SETSIG:
-               rc = smk_curacc(file->f_security, MAY_WRITE);
+               rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
                break;
        default:
-               rc = smk_curacc(file->f_security, MAY_READWRITE);
+               rc = smk_curacc(file->f_security, MAY_READWRITE, &ad);
        }
 
        return rc;
@@ -944,14 +1033,21 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
 {
        struct file *file;
        int rc;
+       char *tsp = tsk->cred->security;
+       struct smk_audit_info ad;
 
        /*
         * struct fown_struct is never outside the context of a struct file
         */
        file = container_of(fown, struct file, f_owner);
-       rc = smk_access(file->f_security, tsk->cred->security, MAY_WRITE);
+       /* we don't log here as rc can be overriden */
+       rc = smk_access(file->f_security, tsp, MAY_WRITE, NULL);
        if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
-               return 0;
+               rc = 0;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
+       smk_ad_setfield_u_tsk(&ad, tsk);
+       smack_log(file->f_security, tsp, MAY_WRITE, rc, &ad);
        return rc;
 }
 
@@ -964,7 +1060,10 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
 static int smack_file_receive(struct file *file)
 {
        int may = 0;
+       struct smk_audit_info ad;
 
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
+       smk_ad_setfield_u_fs_path(&ad, file->f_path);
        /*
         * This code relies on bitmasks.
         */
@@ -973,7 +1072,7 @@ static int smack_file_receive(struct file *file)
        if (file->f_mode & FMODE_WRITE)
                may |= MAY_WRITE;
 
-       return smk_curacc(file->f_security, may);
+       return smk_curacc(file->f_security, may, &ad);
 }
 
 /*
@@ -1052,6 +1151,22 @@ static int smack_kernel_create_files_as(struct cred *new,
        return 0;
 }
 
+/**
+ * smk_curacc_on_task - helper to log task related access
+ * @p: the task object
+ * @access : the access requested
+ *
+ * Return 0 if access is permitted
+ */
+static int smk_curacc_on_task(struct task_struct *p, int access)
+{
+       struct smk_audit_info ad;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
+       smk_ad_setfield_u_tsk(&ad, p);
+       return smk_curacc(task_security(p), access, &ad);
+}
+
 /**
  * smack_task_setpgid - Smack check on setting pgid
  * @p: the task object
@@ -1061,7 +1176,7 @@ static int smack_kernel_create_files_as(struct cred *new,
  */
 static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
 {
-       return smk_curacc(task_security(p), MAY_WRITE);
+       return smk_curacc_on_task(p, MAY_WRITE);
 }
 
 /**
@@ -1072,7 +1187,7 @@ static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
  */
 static int smack_task_getpgid(struct task_struct *p)
 {
-       return smk_curacc(task_security(p), MAY_READ);
+       return smk_curacc_on_task(p, MAY_READ);
 }
 
 /**
@@ -1083,7 +1198,7 @@ static int smack_task_getpgid(struct task_struct *p)
  */
 static int smack_task_getsid(struct task_struct *p)
 {
-       return smk_curacc(task_security(p), MAY_READ);
+       return smk_curacc_on_task(p, MAY_READ);
 }
 
 /**
@@ -1111,7 +1226,7 @@ static int smack_task_setnice(struct task_struct *p, int nice)
 
        rc = cap_task_setnice(p, nice);
        if (rc == 0)
-               rc = smk_curacc(task_security(p), MAY_WRITE);
+               rc = smk_curacc_on_task(p, MAY_WRITE);
        return rc;
 }
 
@@ -1128,7 +1243,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio)
 
        rc = cap_task_setioprio(p, ioprio);
        if (rc == 0)
-               rc = smk_curacc(task_security(p), MAY_WRITE);
+               rc = smk_curacc_on_task(p, MAY_WRITE);
        return rc;
 }
 
@@ -1140,7 +1255,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio)
  */
 static int smack_task_getioprio(struct task_struct *p)
 {
-       return smk_curacc(task_security(p), MAY_READ);
+       return smk_curacc_on_task(p, MAY_READ);
 }
 
 /**
@@ -1158,7 +1273,7 @@ static int smack_task_setscheduler(struct task_struct *p, int policy,
 
        rc = cap_task_setscheduler(p, policy, lp);
        if (rc == 0)
-               rc = smk_curacc(task_security(p), MAY_WRITE);
+               rc = smk_curacc_on_task(p, MAY_WRITE);
        return rc;
 }
 
@@ -1170,7 +1285,7 @@ static int smack_task_setscheduler(struct task_struct *p, int policy,
  */
 static int smack_task_getscheduler(struct task_struct *p)
 {
-       return smk_curacc(task_security(p), MAY_READ);
+       return smk_curacc_on_task(p, MAY_READ);
 }
 
 /**
@@ -1181,7 +1296,7 @@ static int smack_task_getscheduler(struct task_struct *p)
  */
 static int smack_task_movememory(struct task_struct *p)
 {
-       return smk_curacc(task_security(p), MAY_WRITE);
+       return smk_curacc_on_task(p, MAY_WRITE);
 }
 
 /**
@@ -1199,18 +1314,23 @@ static int smack_task_movememory(struct task_struct *p)
 static int smack_task_kill(struct task_struct *p, struct siginfo *info,
                           int sig, u32 secid)
 {
+       struct smk_audit_info ad;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
+       smk_ad_setfield_u_tsk(&ad, p);
        /*
         * Sending a signal requires that the sender
         * can write the receiver.
         */
        if (secid == 0)
-               return smk_curacc(task_security(p), MAY_WRITE);
+               return smk_curacc(task_security(p), MAY_WRITE, &ad);
        /*
         * If the secid isn't 0 we're dealing with some USB IO
         * specific behavior. This is not clean. For one thing
         * we can't take privilege into account.
         */
-       return smk_access(smack_from_secid(secid), task_security(p), MAY_WRITE);
+       return smk_access(smack_from_secid(secid), task_security(p),
+                         MAY_WRITE, &ad);
 }
 
 /**
@@ -1221,11 +1341,15 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
  */
 static int smack_task_wait(struct task_struct *p)
 {
+       struct smk_audit_info ad;
+       char *sp = current_security();
+       char *tsp = task_security(p);
        int rc;
 
-       rc = smk_access(current_security(), task_security(p), MAY_WRITE);
+       /* we don't log here, we can be overriden */
+       rc = smk_access(sp, tsp, MAY_WRITE, NULL);
        if (rc == 0)
-               return 0;
+               goto out_log;
 
        /*
         * Allow the operation to succeed if either task
@@ -1239,8 +1363,12 @@ static int smack_task_wait(struct task_struct *p)
         * the smack value.
         */
        if (capable(CAP_MAC_OVERRIDE) || has_capability(p, CAP_MAC_OVERRIDE))
-               return 0;
-
+               rc = 0;
+       /* we log only if we didn't get overriden */
+ out_log:
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
+       smk_ad_setfield_u_tsk(&ad, p);
+       smack_log(sp, tsp, MAY_WRITE, rc, &ad);
        return rc;
 }
 
@@ -1456,12 +1584,19 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
        int sk_lbl;
        char *hostsp;
        struct socket_smack *ssp = sk->sk_security;
+       struct smk_audit_info ad;
 
        rcu_read_lock();
        hostsp = smack_host_label(sap);
        if (hostsp != NULL) {
                sk_lbl = SMACK_UNLABELED_SOCKET;
-               rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
+#ifdef CONFIG_AUDIT
+               smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
+               ad.a.u.net.family = sap->sin_family;
+               ad.a.u.net.dport = sap->sin_port;
+               ad.a.u.net.v4info.daddr = sap->sin_addr.s_addr;
+#endif
+               rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE, &ad);
        } else {
                sk_lbl = SMACK_CIPSO_SOCKET;
                rc = 0;
@@ -1656,6 +1791,25 @@ static void smack_shm_free_security(struct shmid_kernel *shp)
        isp->security = NULL;
 }
 
+/**
+ * smk_curacc_shm : check if current has access on shm
+ * @shp : the object
+ * @access : access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smk_curacc_shm(struct shmid_kernel *shp, int access)
+{
+       char *ssp = smack_of_shm(shp);
+       struct smk_audit_info ad;
+
+#ifdef CONFIG_AUDIT
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
+       ad.a.u.ipc_id = shp->shm_perm.id;
+#endif
+       return smk_curacc(ssp, access, &ad);
+}
+
 /**
  * smack_shm_associate - Smack access check for shm
  * @shp: the object
@@ -1665,11 +1819,10 @@ static void smack_shm_free_security(struct shmid_kernel *shp)
  */
 static int smack_shm_associate(struct shmid_kernel *shp, int shmflg)
 {
-       char *ssp = smack_of_shm(shp);
        int may;
 
        may = smack_flags_to_may(shmflg);
-       return smk_curacc(ssp, may);
+       return smk_curacc_shm(shp, may);
 }
 
 /**
@@ -1681,7 +1834,6 @@ static int smack_shm_associate(struct shmid_kernel *shp, int shmflg)
  */
 static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd)
 {
-       char *ssp;
        int may;
 
        switch (cmd) {
@@ -1704,9 +1856,7 @@ static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd)
        default:
                return -EINVAL;
        }
-
-       ssp = smack_of_shm(shp);
-       return smk_curacc(ssp, may);
+       return smk_curacc_shm(shp, may);
 }
 
 /**
@@ -1720,11 +1870,10 @@ static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd)
 static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
                           int shmflg)
 {
-       char *ssp = smack_of_shm(shp);
        int may;
 
        may = smack_flags_to_may(shmflg);
-       return smk_curacc(ssp, may);
+       return smk_curacc_shm(shp, may);
 }
 
 /**
@@ -1765,6 +1914,25 @@ static void smack_sem_free_security(struct sem_array *sma)
        isp->security = NULL;
 }
 
+/**
+ * smk_curacc_sem : check if current has access on sem
+ * @sma : the object
+ * @access : access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smk_curacc_sem(struct sem_array *sma, int access)
+{
+       char *ssp = smack_of_sem(sma);
+       struct smk_audit_info ad;
+
+#ifdef CONFIG_AUDIT
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
+       ad.a.u.ipc_id = sma->sem_perm.id;
+#endif
+       return smk_curacc(ssp, access, &ad);
+}
+
 /**
  * smack_sem_associate - Smack access check for sem
  * @sma: the object
@@ -1774,11 +1942,10 @@ static void smack_sem_free_security(struct sem_array *sma)
  */
 static int smack_sem_associate(struct sem_array *sma, int semflg)
 {
-       char *ssp = smack_of_sem(sma);
        int may;
 
        may = smack_flags_to_may(semflg);
-       return smk_curacc(ssp, may);
+       return smk_curacc_sem(sma, may);
 }
 
 /**
@@ -1790,7 +1957,6 @@ static int smack_sem_associate(struct sem_array *sma, int semflg)
  */
 static int smack_sem_semctl(struct sem_array *sma, int cmd)
 {
-       char *ssp;
        int may;
 
        switch (cmd) {
@@ -1819,8 +1985,7 @@ static int smack_sem_semctl(struct sem_array *sma, int cmd)
                return -EINVAL;
        }
 
-       ssp = smack_of_sem(sma);
-       return smk_curacc(ssp, may);
+       return smk_curacc_sem(sma, may);
 }
 
 /**
@@ -1837,9 +2002,7 @@ static int smack_sem_semctl(struct sem_array *sma, int cmd)
 static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops,
                           unsigned nsops, int alter)
 {
-       char *ssp = smack_of_sem(sma);
-
-       return smk_curacc(ssp, MAY_READWRITE);
+       return smk_curacc_sem(sma, MAY_READWRITE);
 }
 
 /**
@@ -1880,6 +2043,25 @@ static char *smack_of_msq(struct msg_queue *msq)
        return (char *)msq->q_perm.security;
 }
 
+/**
+ * smk_curacc_msq : helper to check if current has access on msq
+ * @msq : the msq
+ * @access : access requested
+ *
+ * return 0 if current has access, error otherwise
+ */
+static int smk_curacc_msq(struct msg_queue *msq, int access)
+{
+       char *msp = smack_of_msq(msq);
+       struct smk_audit_info ad;
+
+#ifdef CONFIG_AUDIT
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
+       ad.a.u.ipc_id = msq->q_perm.id;
+#endif
+       return smk_curacc(msp, access, &ad);
+}
+
 /**
  * smack_msg_queue_associate - Smack access check for msg_queue
  * @msq: the object
@@ -1889,11 +2071,10 @@ static char *smack_of_msq(struct msg_queue *msq)
  */
 static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg)
 {
-       char *msp = smack_of_msq(msq);
        int may;
 
        may = smack_flags_to_may(msqflg);
-       return smk_curacc(msp, may);
+       return smk_curacc_msq(msq, may);
 }
 
 /**
@@ -1905,7 +2086,6 @@ static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg)
  */
 static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd)
 {
-       char *msp;
        int may;
 
        switch (cmd) {
@@ -1927,8 +2107,7 @@ static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd)
                return -EINVAL;
        }
 
-       msp = smack_of_msq(msq);
-       return smk_curacc(msp, may);
+       return smk_curacc_msq(msq, may);
 }
 
 /**
@@ -1942,11 +2121,10 @@ static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd)
 static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
                                  int msqflg)
 {
-       char *msp = smack_of_msq(msq);
-       int rc;
+       int may;
 
-       rc = smack_flags_to_may(msqflg);
-       return smk_curacc(msp, rc);
+       may = smack_flags_to_may(msqflg);
+       return smk_curacc_msq(msq, may);
 }
 
 /**
@@ -1962,9 +2140,7 @@ static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
 static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
                        struct task_struct *target, long type, int mode)
 {
-       char *msp = smack_of_msq(msq);
-
-       return smk_curacc(msp, MAY_READWRITE);
+       return smk_curacc_msq(msq, MAY_READWRITE);
 }
 
 /**
@@ -1977,10 +2153,14 @@ static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
 {
        char *isp = ipp->security;
-       int may;
+       int may = smack_flags_to_may(flag);
+       struct smk_audit_info ad;
 
-       may = smack_flags_to_may(flag);
-       return smk_curacc(isp, may);
+#ifdef CONFIG_AUDIT
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
+       ad.a.u.ipc_id = ipp->id;
+#endif
+       return smk_curacc(isp, may, &ad);
 }
 
 /**
@@ -2239,8 +2419,12 @@ static int smack_unix_stream_connect(struct socket *sock,
 {
        struct inode *sp = SOCK_INODE(sock);
        struct inode *op = SOCK_INODE(other);
+       struct smk_audit_info ad;
 
-       return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_READWRITE);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
+       smk_ad_setfield_u_net_sk(&ad, other->sk);
+       return smk_access(smk_of_inode(sp), smk_of_inode(op),
+                                MAY_READWRITE, &ad);
 }
 
 /**
@@ -2255,8 +2439,11 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
 {
        struct inode *sp = SOCK_INODE(sock);
        struct inode *op = SOCK_INODE(other);
+       struct smk_audit_info ad;
 
-       return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
+       smk_ad_setfield_u_net_sk(&ad, other->sk);
+       return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE, &ad);
 }
 
 /**
@@ -2371,7 +2558,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        char smack[SMK_LABELLEN];
        char *csp;
        int rc;
-
+       struct smk_audit_info ad;
        if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
                return 0;
 
@@ -2389,13 +2576,19 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
        netlbl_secattr_destroy(&secattr);
 
+#ifdef CONFIG_AUDIT
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
+       ad.a.u.net.family = sk->sk_family;
+       ad.a.u.net.netif = skb->iif;
+       ipv4_skb_to_auditdata(skb, &ad.a, NULL);
+#endif
        /*
         * Receiving a packet requires that the other end
         * be able to write here. Read access is not required.
         * This is the simplist possible security model
         * for networking.
         */
-       rc = smk_access(csp, ssp->smk_in, MAY_WRITE);
+       rc = smk_access(csp, ssp->smk_in, MAY_WRITE, &ad);
        if (rc != 0)
                netlbl_skbuff_err(skb, rc, 0);
        return rc;
@@ -2524,6 +2717,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
        struct iphdr *hdr;
        char smack[SMK_LABELLEN];
        int rc;
+       struct smk_audit_info ad;
 
        /* handle mapped IPv4 packets arriving via IPv6 sockets */
        if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
@@ -2537,11 +2731,17 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
                strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN);
        netlbl_secattr_destroy(&secattr);
 
+#ifdef CONFIG_AUDIT
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
+       ad.a.u.net.family = family;
+       ad.a.u.net.netif = skb->iif;
+       ipv4_skb_to_auditdata(skb, &ad.a, NULL);
+#endif
        /*
         * Receiving a packet requires that the other end be able to write
         * here. Read access is not required.
         */
-       rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
+       rc = smk_access(smack, ssp->smk_in, MAY_WRITE, &ad);
        if (rc != 0)
                return rc;
 
@@ -2643,6 +2843,7 @@ static int smack_key_permission(key_ref_t key_ref,
                                const struct cred *cred, key_perm_t perm)
 {
        struct key *keyp;
+       struct smk_audit_info ad;
 
        keyp = key_ref_to_ptr(key_ref);
        if (keyp == NULL)
@@ -2658,8 +2859,13 @@ static int smack_key_permission(key_ref_t key_ref,
         */
        if (cred->security == NULL)
                return -EACCES;
-
-       return smk_access(cred->security, keyp->security, MAY_READWRITE);
+#ifdef CONFIG_AUDIT
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY);
+       ad.a.u.key_struct.key = keyp->serial;
+       ad.a.u.key_struct.key_desc = keyp->description;
+#endif
+       return smk_access(cred->security, keyp->security,
+                                MAY_READWRITE, &ad);
 }
 #endif /* CONFIG_KEYS */
 
@@ -2828,15 +3034,7 @@ struct security_operations smack_ops = {
 
        .ptrace_may_access =            smack_ptrace_may_access,
        .ptrace_traceme =               smack_ptrace_traceme,
-       .capget =                       cap_capget,
-       .capset =                       cap_capset,
-       .capable =                      cap_capable,
        .syslog =                       smack_syslog,
-       .settime =                      cap_settime,
-       .vm_enough_memory =             cap_vm_enough_memory,
-
-       .bprm_set_creds =               cap_bprm_set_creds,
-       .bprm_secureexec =              cap_bprm_secureexec,
 
        .sb_alloc_security =            smack_sb_alloc_security,
        .sb_free_security =             smack_sb_free_security,
@@ -2860,8 +3058,6 @@ struct security_operations smack_ops = {
        .inode_post_setxattr =          smack_inode_post_setxattr,
        .inode_getxattr =               smack_inode_getxattr,
        .inode_removexattr =            smack_inode_removexattr,
-       .inode_need_killpriv =          cap_inode_need_killpriv,
-       .inode_killpriv =               cap_inode_killpriv,
        .inode_getsecurity =            smack_inode_getsecurity,
        .inode_setsecurity =            smack_inode_setsecurity,
        .inode_listsecurity =           smack_inode_listsecurity,
@@ -2882,7 +3078,6 @@ struct security_operations smack_ops = {
        .cred_commit =                  smack_cred_commit,
        .kernel_act_as =                smack_kernel_act_as,
        .kernel_create_files_as =       smack_kernel_create_files_as,
-       .task_fix_setuid =              cap_task_fix_setuid,
        .task_setpgid =                 smack_task_setpgid,
        .task_getpgid =                 smack_task_getpgid,
        .task_getsid =                  smack_task_getsid,
@@ -2896,7 +3091,6 @@ struct security_operations smack_ops = {
        .task_kill =                    smack_task_kill,
        .task_wait =                    smack_task_wait,
        .task_to_inode =                smack_task_to_inode,
-       .task_prctl =                   cap_task_prctl,
 
        .ipc_permission =               smack_ipc_permission,
        .ipc_getsecid =                 smack_ipc_getsecid,
@@ -2923,9 +3117,6 @@ struct security_operations smack_ops = {
        .sem_semctl =                   smack_sem_semctl,
        .sem_semop =                    smack_sem_semop,
 
-       .netlink_send =                 cap_netlink_send,
-       .netlink_recv =                 cap_netlink_recv,
-
        .d_instantiate =                smack_d_instantiate,
 
        .getprocattr =                  smack_getprocattr,
index e03a7e19c73b3a0b49d7533db45ecb719d250f30..f83a809807263beacdb756adae4696b6cda33309 100644 (file)
@@ -41,6 +41,7 @@ enum smk_inos {
        SMK_AMBIENT     = 7,    /* internet ambient label */
        SMK_NETLBLADDR  = 8,    /* single label hosts */
        SMK_ONLYCAP     = 9,    /* the only "capable" label */
+       SMK_LOGGING     = 10,   /* logging */
 };
 
 /*
@@ -734,8 +735,8 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
                return;
        }
 
-       m = list_entry(rcu_dereference(smk_netlbladdr_list.next),
-                        struct smk_netlbladdr, list);
+       m = list_entry_rcu(smk_netlbladdr_list.next,
+                          struct smk_netlbladdr, list);
 
        /* the comparison '>' is a bit hacky, but works */
        if (new->smk_mask.s_addr > m->smk_mask.s_addr) {
@@ -748,8 +749,8 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
                        list_add_rcu(&new->list, &m->list);
                        return;
                }
-               m_next = list_entry(rcu_dereference(m->list.next),
-                                struct smk_netlbladdr, list);
+               m_next = list_entry_rcu(m->list.next,
+                                       struct smk_netlbladdr, list);
                if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) {
                        list_add_rcu(&new->list, &m->list);
                        return;
@@ -775,7 +776,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
        struct sockaddr_in newname;
        char smack[SMK_LABELLEN];
        char *sp;
-       char data[SMK_NETLBLADDRMAX];
+       char data[SMK_NETLBLADDRMAX + 1];
        char *host = (char *)&newname.sin_addr.s_addr;
        int rc;
        struct netlbl_audit audit_info;
@@ -1191,6 +1192,69 @@ static const struct file_operations smk_onlycap_ops = {
        .write          = smk_write_onlycap,
 };
 
+/**
+ * smk_read_logging - read() for /smack/logging
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @cn: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_logging(struct file *filp, char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       char temp[32];
+       ssize_t rc;
+
+       if (*ppos != 0)
+               return 0;
+
+       sprintf(temp, "%d\n", log_policy);
+       rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
+       return rc;
+}
+
+/**
+ * smk_write_logging - write() for /smack/logging
+ * @file: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_logging(struct file *file, const char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       char temp[32];
+       int i;
+
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+
+       if (count >= sizeof(temp) || count == 0)
+               return -EINVAL;
+
+       if (copy_from_user(temp, buf, count) != 0)
+               return -EFAULT;
+
+       temp[count] = '\0';
+
+       if (sscanf(temp, "%d", &i) != 1)
+               return -EINVAL;
+       if (i < 0 || i > 3)
+               return -EINVAL;
+       log_policy = i;
+       return count;
+}
+
+
+
+static const struct file_operations smk_logging_ops = {
+       .read           = smk_read_logging,
+       .write          = smk_write_logging,
+};
 /**
  * smk_fill_super - fill the /smackfs superblock
  * @sb: the empty superblock
@@ -1221,6 +1285,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
                        {"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR},
                [SMK_ONLYCAP]   =
                        {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
+               [SMK_LOGGING]   =
+                       {"logging", &smk_logging_ops, S_IRUGO|S_IWUSR},
                /* last one */ {""}
        };
 
index ddfb9cccf468aee271c4a84757c5f475a8c47524..fdd1f4b8c448e4c1fa6611bb9456f5e9c9d30070 100644 (file)
@@ -28,7 +28,13 @@ static const char *tomoyo_mode_2[4] = {
        "disabled", "enabled", "enabled", "enabled"
 };
 
-/* Table for profile. */
+/*
+ * tomoyo_control_array is a static data which contains
+ *
+ *  (1) functionality name used by /sys/kernel/security/tomoyo/profile .
+ *  (2) initial values for "struct tomoyo_profile".
+ *  (3) max values for "struct tomoyo_profile".
+ */
 static struct {
        const char *keyword;
        unsigned int current_value;
@@ -39,7 +45,13 @@ static struct {
        [TOMOYO_VERBOSE]          = { "TOMOYO_VERBOSE",      1,       1 },
 };
 
-/* Profile table. Memory is allocated as needed. */
+/*
+ * tomoyo_profile is a structure which is used for holding the mode of access
+ * controls. TOMOYO has 4 modes: disabled, learning, permissive, enforcing.
+ * An administrator can define up to 256 profiles.
+ * The ->profile of "struct tomoyo_domain_info" is used for remembering
+ * the profile's number (0 - 255) assigned to that domain.
+ */
 static struct tomoyo_profile {
        unsigned int value[TOMOYO_MAX_CONTROL_INDEX];
        const struct tomoyo_path_info *comment;
@@ -428,7 +440,6 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
        const char *name = ptr->name;
        const int len = strlen(name);
 
-       ptr->total_len = len;
        ptr->const_len = tomoyo_const_part_length(name);
        ptr->is_dir = len && (name[len - 1] == '/');
        ptr->is_patterned = (ptr->const_len < len);
@@ -866,7 +877,6 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
 
        if (profile >= TOMOYO_MAX_PROFILES)
                return NULL;
-       /***** EXCLUSIVE SECTION START *****/
        mutex_lock(&lock);
        ptr = tomoyo_profile_ptr[profile];
        if (ptr)
@@ -880,7 +890,6 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
        tomoyo_profile_ptr[profile] = ptr;
  ok:
        mutex_unlock(&lock);
-       /***** EXCLUSIVE SECTION END *****/
        return ptr;
 }
 
@@ -1009,7 +1018,19 @@ static int tomoyo_read_profile(struct tomoyo_io_buffer *head)
        return 0;
 }
 
-/* Structure for policy manager. */
+/*
+ * tomoyo_policy_manager_entry is a structure which is used for holding list of
+ * domainnames or programs which are permitted to modify configuration via
+ * /sys/kernel/security/tomoyo/ interface.
+ * It has following fields.
+ *
+ *  (1) "list" which is linked to tomoyo_policy_manager_list .
+ *  (2) "manager" is a domainname or a program's pathname.
+ *  (3) "is_domain" is a bool which is true if "manager" is a domainname, false
+ *      otherwise.
+ *  (4) "is_deleted" is a bool which is true if marked as deleted, false
+ *      otherwise.
+ */
 struct tomoyo_policy_manager_entry {
        struct list_head list;
        /* A path to program or a domainname. */
@@ -1018,7 +1039,36 @@ struct tomoyo_policy_manager_entry {
        bool is_deleted; /* True if this entry is deleted. */
 };
 
-/* The list for "struct tomoyo_policy_manager_entry". */
+/*
+ * tomoyo_policy_manager_list is used for holding list of domainnames or
+ * programs which are permitted to modify configuration via
+ * /sys/kernel/security/tomoyo/ interface.
+ *
+ * An entry is added by
+ *
+ * # echo '<kernel> /sbin/mingetty /bin/login /bin/bash' > \
+ *                                        /sys/kernel/security/tomoyo/manager
+ *  (if you want to specify by a domainname)
+ *
+ *  or
+ *
+ * # echo '/usr/lib/ccs/editpolicy' > /sys/kernel/security/tomoyo/manager
+ *  (if you want to specify by a program's location)
+ *
+ * and is deleted by
+ *
+ * # echo 'delete <kernel> /sbin/mingetty /bin/login /bin/bash' > \
+ *                                        /sys/kernel/security/tomoyo/manager
+ *
+ *  or
+ *
+ * # echo 'delete /usr/lib/ccs/editpolicy' > \
+ *                                        /sys/kernel/security/tomoyo/manager
+ *
+ * and all entries are retrieved by
+ *
+ * # cat /sys/kernel/security/tomoyo/manager
+ */
 static LIST_HEAD(tomoyo_policy_manager_list);
 static DECLARE_RWSEM(tomoyo_policy_manager_list_lock);
 
@@ -1050,7 +1100,6 @@ static int tomoyo_update_manager_entry(const char *manager,
        saved_manager = tomoyo_save_name(manager);
        if (!saved_manager)
                return -ENOMEM;
-       /***** EXCLUSIVE SECTION START *****/
        down_write(&tomoyo_policy_manager_list_lock);
        list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
                if (ptr->manager != saved_manager)
@@ -1072,7 +1121,6 @@ static int tomoyo_update_manager_entry(const char *manager,
        error = 0;
  out:
        up_write(&tomoyo_policy_manager_list_lock);
-       /***** EXCLUSIVE SECTION END *****/
        return error;
 }
 
@@ -1117,10 +1165,9 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
                                 list);
                if (ptr->is_deleted)
                        continue;
-               if (!tomoyo_io_printf(head, "%s\n", ptr->manager->name)) {
-                       done = false;
+               done = tomoyo_io_printf(head, "%s\n", ptr->manager->name);
+               if (!done)
                        break;
-               }
        }
        up_read(&tomoyo_policy_manager_list_lock);
        head->read_eof = done;
@@ -1197,13 +1244,11 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
 
        if (sscanf(data, "pid=%u", &pid) == 1) {
                struct task_struct *p;
-               /***** CRITICAL SECTION START *****/
                read_lock(&tasklist_lock);
                p = find_task_by_vpid(pid);
                if (p)
                        domain = tomoyo_real_domain(p);
                read_unlock(&tasklist_lock);
-               /***** CRITICAL SECTION END *****/
        } else if (!strncmp(data, "domain=", 7)) {
                if (tomoyo_is_domain_def(data + 7)) {
                        down_read(&tomoyo_domain_list_lock);
@@ -1447,15 +1492,14 @@ static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
                    TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ)
                        ignore_global_allow_read
                                = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n";
-               if (!tomoyo_io_printf(head,
-                                     "%s\n" TOMOYO_KEYWORD_USE_PROFILE "%u\n"
-                                     "%s%s%s\n", domain->domainname->name,
-                                     domain->profile, quota_exceeded,
-                                     transition_failed,
-                                     ignore_global_allow_read)) {
-                       done = false;
+               done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE
+                                       "%u\n%s%s%s\n",
+                                       domain->domainname->name,
+                                       domain->profile, quota_exceeded,
+                                       transition_failed,
+                                       ignore_global_allow_read);
+               if (!done)
                        break;
-               }
                head->read_step = 2;
 acl_loop:
                if (head->read_step == 3)
@@ -1463,24 +1507,22 @@ acl_loop:
                /* Print ACL entries in the domain. */
                down_read(&tomoyo_domain_acl_info_list_lock);
                list_for_each_cookie(apos, head->read_var2,
-                                     &domain->acl_info_list) {
+                                    &domain->acl_info_list) {
                        struct tomoyo_acl_info *ptr
                                = list_entry(apos, struct tomoyo_acl_info,
-                                             list);
-                       if (!tomoyo_print_entry(head, ptr)) {
-                               done = false;
+                                            list);
+                       done = tomoyo_print_entry(head, ptr);
+                       if (!done)
                                break;
-                       }
                }
                up_read(&tomoyo_domain_acl_info_list_lock);
                if (!done)
                        break;
                head->read_step = 3;
 tail_mark:
-               if (!tomoyo_io_printf(head, "\n")) {
-                       done = false;
+               done = tomoyo_io_printf(head, "\n");
+               if (!done)
                        break;
-               }
                head->read_step = 1;
                if (head->read_single_domain)
                        break;
@@ -1550,11 +1592,10 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
                domain = list_entry(pos, struct tomoyo_domain_info, list);
                if (domain->is_deleted)
                        continue;
-               if (!tomoyo_io_printf(head, "%u %s\n", domain->profile,
-                                     domain->domainname->name)) {
-                       done = false;
+               done = tomoyo_io_printf(head, "%u %s\n", domain->profile,
+                                       domain->domainname->name);
+               if (!done)
                        break;
-               }
        }
        up_read(&tomoyo_domain_list_lock);
        head->read_eof = done;
@@ -1594,13 +1635,11 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head)
                const int pid = head->read_step;
                struct task_struct *p;
                struct tomoyo_domain_info *domain = NULL;
-               /***** CRITICAL SECTION START *****/
                read_lock(&tasklist_lock);
                p = find_task_by_vpid(pid);
                if (p)
                        domain = tomoyo_real_domain(p);
                read_unlock(&tasklist_lock);
-               /***** CRITICAL SECTION END *****/
                if (domain)
                        tomoyo_io_printf(head, "%d %u %s", pid, domain->profile,
                                         domain->domainname->name);
@@ -2138,7 +2177,13 @@ static ssize_t tomoyo_write(struct file *file, const char __user *buf,
        return tomoyo_write_control(file, buf, count);
 }
 
-/* Operations for /sys/kernel/security/tomoyo/ interface. */
+/*
+ * tomoyo_operations is a "struct file_operations" which is used for handling
+ * /sys/kernel/security/tomoyo/ interface.
+ *
+ * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR).
+ * See tomoyo_io_buffer for internals.
+ */
 static const struct file_operations tomoyo_operations = {
        .open    = tomoyo_open,
        .release = tomoyo_release,
index 678f4ff16aa4477eb7b6f4e44d744dc6aac4f932..6d6ba09af4576b27d6aba92edad7d3c7b03515b3 100644 (file)
 struct dentry;
 struct vfsmount;
 
-/* Temporary buffer for holding pathnames. */
+/*
+ * tomoyo_page_buffer is a structure which is used for holding a pathname
+ * obtained from "struct dentry" and "struct vfsmount" pair.
+ * As of now, it is 4096 bytes. If users complain that 4096 bytes is too small
+ * (because TOMOYO escapes non ASCII printable characters using \ooo format),
+ * we will make the buffer larger.
+ */
 struct tomoyo_page_buffer {
        char buffer[4096];
 };
 
-/* Structure for holding a token. */
+/*
+ * tomoyo_path_info is a structure which is used for holding a string data
+ * used by TOMOYO.
+ * This structure has several fields for supporting pattern matching.
+ *
+ * (1) "name" is the '\0' terminated string data.
+ * (2) "hash" is full_name_hash(name, strlen(name)).
+ *     This allows tomoyo_pathcmp() to compare by hash before actually compare
+ *     using strcmp().
+ * (3) "const_len" is the length of the initial segment of "name" which
+ *     consists entirely of non wildcard characters. In other words, the length
+ *     which we can compare two strings using strncmp().
+ * (4) "is_dir" is a bool which is true if "name" ends with "/",
+ *     false otherwise.
+ *     TOMOYO distinguishes directory and non-directory. A directory ends with
+ *     "/" and non-directory does not end with "/".
+ * (5) "is_patterned" is a bool which is true if "name" contains wildcard
+ *     characters, false otherwise. This allows TOMOYO to use "hash" and
+ *     strcmp() for string comparison if "is_patterned" is false.
+ * (6) "depth" is calculated using the number of "/" characters in "name".
+ *     This allows TOMOYO to avoid comparing two pathnames which never match
+ *     (e.g. whether "/var/www/html/index.html" matches "/tmp/sh-thd-\$").
+ */
 struct tomoyo_path_info {
        const char *name;
        u32 hash;          /* = full_name_hash(name, strlen(name)) */
-       u16 total_len;     /* = strlen(name)                       */
        u16 const_len;     /* = tomoyo_const_part_length(name)     */
        bool is_dir;       /* = tomoyo_strendswith(name, "/")      */
        bool is_patterned; /* = tomoyo_path_contains_pattern(name) */
@@ -51,7 +78,20 @@ struct tomoyo_path_info {
  */
 #define TOMOYO_MAX_PATHNAME_LEN 4000
 
-/* Structure for holding requested pathname. */
+/*
+ * tomoyo_path_info_with_data is a structure which is used for holding a
+ * pathname obtained from "struct dentry" and "struct vfsmount" pair.
+ *
+ * "struct tomoyo_path_info_with_data" consists of "struct tomoyo_path_info"
+ * and buffer for the pathname, while "struct tomoyo_page_buffer" consists of
+ * buffer for the pathname only.
+ *
+ * "struct tomoyo_path_info_with_data" is intended to allow TOMOYO to release
+ * both "struct tomoyo_path_info" and buffer for the pathname by single kfree()
+ * so that we don't need to return two pointers to the caller. If the caller
+ * puts "struct tomoyo_path_info" on stack memory, we will be able to remove
+ * "struct tomoyo_path_info_with_data".
+ */
 struct tomoyo_path_info_with_data {
        /* Keep "head" first, for this pointer is passed to tomoyo_free(). */
        struct tomoyo_path_info head;
@@ -61,7 +101,15 @@ struct tomoyo_path_info_with_data {
 };
 
 /*
- * Common header for holding ACL entries.
+ * tomoyo_acl_info is a structure which is used for holding
+ *
+ *  (1) "list" which is linked to the ->acl_info_list of
+ *      "struct tomoyo_domain_info"
+ *  (2) "type" which tells
+ *      (a) type & 0x7F : type of the entry (either
+ *          "struct tomoyo_single_path_acl_record" or
+ *          "struct tomoyo_double_path_acl_record")
+ *      (b) type & 0x80 : whether the entry is marked as "deleted".
  *
  * Packing "struct tomoyo_acl_info" allows
  * "struct tomoyo_single_path_acl_record" to embed "u16" and
@@ -81,7 +129,28 @@ struct tomoyo_acl_info {
 /* This ACL entry is deleted.           */
 #define TOMOYO_ACL_DELETED        0x80
 
-/* Structure for domain information. */
+/*
+ * tomoyo_domain_info is a structure which is used for holding permissions
+ * (e.g. "allow_read /lib/libc-2.5.so") given to each domain.
+ * It has following fields.
+ *
+ *  (1) "list" which is linked to tomoyo_domain_list .
+ *  (2) "acl_info_list" which is linked to "struct tomoyo_acl_info".
+ *  (3) "domainname" which holds the name of the domain.
+ *  (4) "profile" which remembers profile number assigned to this domain.
+ *  (5) "is_deleted" is a bool which is true if this domain is marked as
+ *      "deleted", false otherwise.
+ *  (6) "quota_warned" is a bool which is used for suppressing warning message
+ *      when learning mode learned too much entries.
+ *  (7) "flags" which remembers this domain's attributes.
+ *
+ * A domain's lifecycle is an analogy of files on / directory.
+ * Multiple domains with the same domainname cannot be created (as with
+ * creating files with the same filename fails with -EEXIST).
+ * If a process reached a domain, that process can reside in that domain after
+ * that domain is marked as "deleted" (as with a process can access an already
+ * open()ed file after that file was unlink()ed).
+ */
 struct tomoyo_domain_info {
        struct list_head list;
        struct list_head acl_info_list;
@@ -108,10 +177,18 @@ struct tomoyo_domain_info {
 #define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED        2
 
 /*
- * Structure for "allow_read/write", "allow_execute", "allow_read",
- * "allow_write", "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir",
- * "allow_mkfifo", "allow_mksock", "allow_mkblock", "allow_mkchar",
- * "allow_truncate", "allow_symlink" and "allow_rewrite" directive.
+ * tomoyo_single_path_acl_record is a structure which is used for holding an
+ * entry with one pathname operation (e.g. open(), mkdir()).
+ * It has following fields.
+ *
+ *  (1) "head" which is a "struct tomoyo_acl_info".
+ *  (2) "perm" which is a bitmask of permitted operations.
+ *  (3) "filename" is the pathname.
+ *
+ * Directives held by this structure are "allow_read/write", "allow_execute",
+ * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir",
+ * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock",
+ * "allow_mkchar", "allow_truncate", "allow_symlink" and "allow_rewrite".
  */
 struct tomoyo_single_path_acl_record {
        struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */
@@ -120,7 +197,18 @@ struct tomoyo_single_path_acl_record {
        const struct tomoyo_path_info *filename;
 };
 
-/* Structure for "allow_rename" and "allow_link" directive. */
+/*
+ * tomoyo_double_path_acl_record is a structure which is used for holding an
+ * entry with two pathnames operation (i.e. link() and rename()).
+ * It has following fields.
+ *
+ *  (1) "head" which is a "struct tomoyo_acl_info".
+ *  (2) "perm" which is a bitmask of permitted operations.
+ *  (3) "filename1" is the source/old pathname.
+ *  (4) "filename2" is the destination/new pathname.
+ *
+ * Directives held by this structure are "allow_rename" and "allow_link".
+ */
 struct tomoyo_double_path_acl_record {
        struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */
        u8 perm;
@@ -153,7 +241,29 @@ struct tomoyo_double_path_acl_record {
 #define TOMOYO_VERBOSE                       2
 #define TOMOYO_MAX_CONTROL_INDEX             3
 
-/* Structure for reading/writing policy via securityfs interfaces. */
+/*
+ * tomoyo_io_buffer is a structure which is used for reading and modifying
+ * configuration via /sys/kernel/security/tomoyo/ interface.
+ * It has many fields. ->read_var1 , ->read_var2 , ->write_var1 are used as
+ * cursors.
+ *
+ * Since the content of /sys/kernel/security/tomoyo/domain_policy is a list of
+ * "struct tomoyo_domain_info" entries and each "struct tomoyo_domain_info"
+ * entry has a list of "struct tomoyo_acl_info", we need two cursors when
+ * reading (one is for traversing tomoyo_domain_list and the other is for
+ * traversing "struct tomoyo_acl_info"->acl_info_list ).
+ *
+ * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
+ * "select ", TOMOYO seeks the cursor ->read_var1 and ->write_var1 to the
+ * domain with the domainname specified by the rest of that line (NULL is set
+ * if seek failed).
+ * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
+ * "delete ", TOMOYO deletes an entry or a domain specified by the rest of that
+ * line (->write_var1 is set to NULL if a domain was deleted).
+ * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
+ * neither "select " nor "delete ", an entry or a domain specified by that line
+ * is appended.
+ */
 struct tomoyo_io_buffer {
        int (*read) (struct tomoyo_io_buffer *);
        int (*write) (struct tomoyo_io_buffer *);
index 2d6748741a26e4f08e28872d79d846d06e07c6c7..1d8b16960576891615d7d523626d527030cf31bc 100644 (file)
 /* The initial domain. */
 struct tomoyo_domain_info tomoyo_kernel_domain;
 
-/* The list for "struct tomoyo_domain_info". */
+/*
+ * tomoyo_domain_list is used for holding list of domains.
+ * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding
+ * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain.
+ *
+ * An entry is added by
+ *
+ * # ( echo "<kernel>"; echo "allow_execute /sbin/init" ) > \
+ *                                  /sys/kernel/security/tomoyo/domain_policy
+ *
+ * and is deleted by
+ *
+ * # ( echo "<kernel>"; echo "delete allow_execute /sbin/init" ) > \
+ *                                  /sys/kernel/security/tomoyo/domain_policy
+ *
+ * and all entries are retrieved by
+ *
+ * # cat /sys/kernel/security/tomoyo/domain_policy
+ *
+ * A domain is added by
+ *
+ * # echo "<kernel>" > /sys/kernel/security/tomoyo/domain_policy
+ *
+ * and is deleted by
+ *
+ * # echo "delete <kernel>" > /sys/kernel/security/tomoyo/domain_policy
+ *
+ * and all domains are retrieved by
+ *
+ * # grep '^<kernel>' /sys/kernel/security/tomoyo/domain_policy
+ *
+ * Normally, a domainname is monotonically getting longer because a domainname
+ * which the process will belong to if an execve() operation succeeds is
+ * defined as a concatenation of "current domainname" + "pathname passed to
+ * execve()".
+ * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for
+ * exceptions.
+ */
 LIST_HEAD(tomoyo_domain_list);
 DECLARE_RWSEM(tomoyo_domain_list_lock);
 
-/* Structure for "initialize_domain" and "no_initialize_domain" keyword. */
+/*
+ * tomoyo_domain_initializer_entry is a structure which is used for holding
+ * "initialize_domain" and "no_initialize_domain" entries.
+ * It has following fields.
+ *
+ *  (1) "list" which is linked to tomoyo_domain_initializer_list .
+ *  (2) "domainname" which is "a domainname" or "the last component of a
+ *      domainname". This field is NULL if "from" clause is not specified.
+ *  (3) "program" which is a program's pathname.
+ *  (4) "is_deleted" is a bool which is true if marked as deleted, false
+ *      otherwise.
+ *  (5) "is_not" is a bool which is true if "no_initialize_domain", false
+ *      otherwise.
+ *  (6) "is_last_name" is a bool which is true if "domainname" is "the last
+ *      component of a domainname", false otherwise.
+ */
 struct tomoyo_domain_initializer_entry {
        struct list_head list;
        const struct tomoyo_path_info *domainname;    /* This may be NULL */
@@ -34,7 +86,23 @@ struct tomoyo_domain_initializer_entry {
        bool is_last_name;
 };
 
-/* Structure for "keep_domain" and "no_keep_domain" keyword. */
+/*
+ * tomoyo_domain_keeper_entry is a structure which is used for holding
+ * "keep_domain" and "no_keep_domain" entries.
+ * It has following fields.
+ *
+ *  (1) "list" which is linked to tomoyo_domain_keeper_list .
+ *  (2) "domainname" which is "a domainname" or "the last component of a
+ *      domainname".
+ *  (3) "program" which is a program's pathname.
+ *      This field is NULL if "from" clause is not specified.
+ *  (4) "is_deleted" is a bool which is true if marked as deleted, false
+ *      otherwise.
+ *  (5) "is_not" is a bool which is true if "no_initialize_domain", false
+ *      otherwise.
+ *  (6) "is_last_name" is a bool which is true if "domainname" is "the last
+ *      component of a domainname", false otherwise.
+ */
 struct tomoyo_domain_keeper_entry {
        struct list_head list;
        const struct tomoyo_path_info *domainname;
@@ -45,7 +113,16 @@ struct tomoyo_domain_keeper_entry {
        bool is_last_name;
 };
 
-/* Structure for "alias" keyword. */
+/*
+ * tomoyo_alias_entry is a structure which is used for holding "alias" entries.
+ * It has following fields.
+ *
+ *  (1) "list" which is linked to tomoyo_alias_list .
+ *  (2) "original_name" which is a dereferenced pathname.
+ *  (3) "aliased_name" which is a symlink's pathname.
+ *  (4) "is_deleted" is a bool which is true if marked as deleted, false
+ *      otherwise.
+ */
 struct tomoyo_alias_entry {
        struct list_head list;
        const struct tomoyo_path_info *original_name;
@@ -67,14 +144,12 @@ void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
 {
        /* We need to serialize because this is bitfield operation. */
        static DEFINE_SPINLOCK(lock);
-       /***** CRITICAL SECTION START *****/
        spin_lock(&lock);
        if (!is_delete)
                domain->flags |= flags;
        else
                domain->flags &= ~flags;
        spin_unlock(&lock);
-       /***** CRITICAL SECTION END *****/
 }
 
 /**
@@ -94,7 +169,42 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
        return cp0;
 }
 
-/* The list for "struct tomoyo_domain_initializer_entry". */
+/*
+ * tomoyo_domain_initializer_list is used for holding list of programs which
+ * triggers reinitialization of domainname. Normally, a domainname is
+ * monotonically getting longer. But sometimes, we restart daemon programs.
+ * It would be convenient for us that "a daemon started upon system boot" and
+ * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO
+ * provides a way to shorten domainnames.
+ *
+ * An entry is added by
+ *
+ * # echo 'initialize_domain /usr/sbin/httpd' > \
+ *                               /sys/kernel/security/tomoyo/exception_policy
+ *
+ * and is deleted by
+ *
+ * # echo 'delete initialize_domain /usr/sbin/httpd' > \
+ *                               /sys/kernel/security/tomoyo/exception_policy
+ *
+ * and all entries are retrieved by
+ *
+ * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy
+ *
+ * In the example above, /usr/sbin/httpd will belong to
+ * "<kernel> /usr/sbin/httpd" domain.
+ *
+ * You may specify a domainname using "from" keyword.
+ * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
+ * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd"
+ * domain to belong to "<kernel> /usr/sbin/httpd" domain.
+ *
+ * You may add "no_" prefix to "initialize_domain".
+ * "initialize_domain /usr/sbin/httpd" and
+ * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
+ * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain
+ * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain.
+ */
 static LIST_HEAD(tomoyo_domain_initializer_list);
 static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock);
 
@@ -135,7 +245,6 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
        saved_program = tomoyo_save_name(program);
        if (!saved_program)
                return -ENOMEM;
-       /***** EXCLUSIVE SECTION START *****/
        down_write(&tomoyo_domain_initializer_list_lock);
        list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
                if (ptr->is_not != is_not ||
@@ -161,7 +270,6 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
        error = 0;
  out:
        up_write(&tomoyo_domain_initializer_list_lock);
-       /***** EXCLUSIVE SECTION END *****/
        return error;
 }
 
@@ -193,13 +301,12 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
                        from = " from ";
                        domain = ptr->domainname->name;
                }
-               if (!tomoyo_io_printf(head,
-                                     "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
-                                     "%s%s%s\n", no, ptr->program->name, from,
-                                     domain)) {
-                       done = false;
+               done = tomoyo_io_printf(head,
+                                       "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
+                                       "%s%s%s\n", no, ptr->program->name,
+                                       from, domain);
+               if (!done)
                        break;
-               }
        }
        up_read(&tomoyo_domain_initializer_list_lock);
        return done;
@@ -273,7 +380,44 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
        return flag;
 }
 
-/* The list for "struct tomoyo_domain_keeper_entry". */
+/*
+ * tomoyo_domain_keeper_list is used for holding list of domainnames which
+ * suppresses domain transition. Normally, a domainname is monotonically
+ * getting longer. But sometimes, we want to suppress domain transition.
+ * It would be convenient for us that programs executed from a login session
+ * belong to the same domain. Thus, TOMOYO provides a way to suppress domain
+ * transition.
+ *
+ * An entry is added by
+ *
+ * # echo 'keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
+ *                              /sys/kernel/security/tomoyo/exception_policy
+ *
+ * and is deleted by
+ *
+ * # echo 'delete keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
+ *                              /sys/kernel/security/tomoyo/exception_policy
+ *
+ * and all entries are retrieved by
+ *
+ * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy
+ *
+ * In the example above, any process which belongs to
+ * "<kernel> /usr/sbin/sshd /bin/bash" domain will remain in that domain,
+ * unless explicitly specified by "initialize_domain" or "no_keep_domain".
+ *
+ * You may specify a program using "from" keyword.
+ * "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash"
+ * will cause "/bin/pwd" executed from "<kernel> /usr/sbin/sshd /bin/bash"
+ * domain to remain in "<kernel> /usr/sbin/sshd /bin/bash" domain.
+ *
+ * You may add "no_" prefix to "keep_domain".
+ * "keep_domain <kernel> /usr/sbin/sshd /bin/bash" and
+ * "no_keep_domain /usr/bin/passwd from <kernel> /usr/sbin/sshd /bin/bash" will
+ * cause "/usr/bin/passwd" to belong to
+ * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless
+ * explicitly specified by "initialize_domain".
+ */
 static LIST_HEAD(tomoyo_domain_keeper_list);
 static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock);
 
@@ -296,7 +440,6 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
        struct tomoyo_domain_keeper_entry *ptr;
        const struct tomoyo_path_info *saved_domainname;
        const struct tomoyo_path_info *saved_program = NULL;
-       static DEFINE_MUTEX(lock);
        int error = -ENOMEM;
        bool is_last_name = false;
 
@@ -315,7 +458,6 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
        saved_domainname = tomoyo_save_name(domainname);
        if (!saved_domainname)
                return -ENOMEM;
-       /***** EXCLUSIVE SECTION START *****/
        down_write(&tomoyo_domain_keeper_list_lock);
        list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
                if (ptr->is_not != is_not ||
@@ -341,7 +483,6 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
        error = 0;
  out:
        up_write(&tomoyo_domain_keeper_list_lock);
-       /***** EXCLUSIVE SECTION END *****/
        return error;
 }
 
@@ -394,13 +535,12 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
                        from = " from ";
                        program = ptr->program->name;
                }
-               if (!tomoyo_io_printf(head,
-                                     "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
-                                     "%s%s%s\n", no, program, from,
-                                     ptr->domainname->name)) {
-                       done = false;
+               done = tomoyo_io_printf(head,
+                                       "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
+                                       "%s%s%s\n", no, program, from,
+                                       ptr->domainname->name);
+               if (!done)
                        break;
-               }
        }
        up_read(&tomoyo_domain_keeper_list_lock);
        return done;
@@ -446,7 +586,36 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
        return flag;
 }
 
-/* The list for "struct tomoyo_alias_entry". */
+/*
+ * tomoyo_alias_list is used for holding list of symlink's pathnames which are
+ * allowed to be passed to an execve() request. Normally, the domainname which
+ * the current process will belong to after execve() succeeds is calculated
+ * using dereferenced pathnames. But some programs behave differently depending
+ * on the name passed to argv[0]. For busybox, calculating domainname using
+ * dereferenced pathnames will cause all programs in the busybox to belong to
+ * the same domain. Thus, TOMOYO provides a way to allow use of symlink's
+ * pathname for checking execve()'s permission and calculating domainname which
+ * the current process will belong to after execve() succeeds.
+ *
+ * An entry is added by
+ *
+ * # echo 'alias /bin/busybox /bin/cat' > \
+ *                            /sys/kernel/security/tomoyo/exception_policy
+ *
+ * and is deleted by
+ *
+ * # echo 'delete alias /bin/busybox /bin/cat' > \
+ *                            /sys/kernel/security/tomoyo/exception_policy
+ *
+ * and all entries are retrieved by
+ *
+ * # grep ^alias /sys/kernel/security/tomoyo/exception_policy
+ *
+ * In the example above, if /bin/cat is a symlink to /bin/busybox and execution
+ * of /bin/cat is requested, permission is checked for /bin/cat rather than
+ * /bin/busybox and domainname which the current process will belong to after
+ * execve() succeeds is calculated using /bin/cat rather than /bin/busybox .
+ */
 static LIST_HEAD(tomoyo_alias_list);
 static DECLARE_RWSEM(tomoyo_alias_list_lock);
 
@@ -476,7 +645,6 @@ static int tomoyo_update_alias_entry(const char *original_name,
        saved_aliased_name = tomoyo_save_name(aliased_name);
        if (!saved_original_name || !saved_aliased_name)
                return -ENOMEM;
-       /***** EXCLUSIVE SECTION START *****/
        down_write(&tomoyo_alias_list_lock);
        list_for_each_entry(ptr, &tomoyo_alias_list, list) {
                if (ptr->original_name != saved_original_name ||
@@ -499,7 +667,6 @@ static int tomoyo_update_alias_entry(const char *original_name,
        error = 0;
  out:
        up_write(&tomoyo_alias_list_lock);
-       /***** EXCLUSIVE SECTION END *****/
        return error;
 }
 
@@ -522,12 +689,11 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
                ptr = list_entry(pos, struct tomoyo_alias_entry, list);
                if (ptr->is_deleted)
                        continue;
-               if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
-                                     ptr->original_name->name,
-                                     ptr->aliased_name->name)) {
-                       done = false;
+               done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
+                                       ptr->original_name->name,
+                                       ptr->aliased_name->name);
+               if (!done)
                        break;
-               }
        }
        up_read(&tomoyo_alias_list_lock);
        return done;
@@ -567,7 +733,6 @@ int tomoyo_delete_domain(char *domainname)
 
        name.name = domainname;
        tomoyo_fill_path_info(&name);
-       /***** EXCLUSIVE SECTION START *****/
        down_write(&tomoyo_domain_list_lock);
        /* Is there an active domain? */
        list_for_each_entry(domain, &tomoyo_domain_list, list) {
@@ -581,7 +746,6 @@ int tomoyo_delete_domain(char *domainname)
                break;
        }
        up_write(&tomoyo_domain_list_lock);
-       /***** EXCLUSIVE SECTION END *****/
        return 0;
 }
 
@@ -600,7 +764,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
        struct tomoyo_domain_info *domain = NULL;
        const struct tomoyo_path_info *saved_domainname;
 
-       /***** EXCLUSIVE SECTION START *****/
        down_write(&tomoyo_domain_list_lock);
        domain = tomoyo_find_domain(domainname);
        if (domain)
@@ -619,7 +782,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
                    domain->domainname != saved_domainname)
                        continue;
                flag = false;
-               /***** CRITICAL SECTION START *****/
                read_lock(&tasklist_lock);
                for_each_process(p) {
                        if (tomoyo_real_domain(p) != domain)
@@ -628,7 +790,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
                        break;
                }
                read_unlock(&tasklist_lock);
-               /***** CRITICAL SECTION END *****/
                if (flag)
                        continue;
                list_for_each_entry(ptr, &domain->acl_info_list, list) {
@@ -651,7 +812,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
        }
  out:
        up_write(&tomoyo_domain_list_lock);
-       /***** EXCLUSIVE SECTION END *****/
        return domain;
 }
 
@@ -739,7 +899,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm,
        }
 
        /* Check execute permission. */
-       retval = tomoyo_check_exec_perm(old_domain, &r, tmp);
+       retval = tomoyo_check_exec_perm(old_domain, &r);
        if (retval < 0)
                goto out;
 
index 2316da8ec5bcaf13485aca9f93bdd0e01b171107..5ae3a571559f58192b7be8a94cada7886706c243 100644 (file)
 #include "realpath.h"
 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
 
-/* Structure for "allow_read" keyword. */
+/*
+ * tomoyo_globally_readable_file_entry is a structure which is used for holding
+ * "allow_read" entries.
+ * It has following fields.
+ *
+ *  (1) "list" which is linked to tomoyo_globally_readable_list .
+ *  (2) "filename" is a pathname which is allowed to open(O_RDONLY).
+ *  (3) "is_deleted" is a bool which is true if marked as deleted, false
+ *      otherwise.
+ */
 struct tomoyo_globally_readable_file_entry {
        struct list_head list;
        const struct tomoyo_path_info *filename;
        bool is_deleted;
 };
 
-/* Structure for "file_pattern" keyword. */
+/*
+ * tomoyo_pattern_entry is a structure which is used for holding
+ * "tomoyo_pattern_list" entries.
+ * It has following fields.
+ *
+ *  (1) "list" which is linked to tomoyo_pattern_list .
+ *  (2) "pattern" is a pathname pattern which is used for converting pathnames
+ *      to pathname patterns during learning mode.
+ *  (3) "is_deleted" is a bool which is true if marked as deleted, false
+ *      otherwise.
+ */
 struct tomoyo_pattern_entry {
        struct list_head list;
        const struct tomoyo_path_info *pattern;
        bool is_deleted;
 };
 
-/* Structure for "deny_rewrite" keyword. */
+/*
+ * tomoyo_no_rewrite_entry is a structure which is used for holding
+ * "deny_rewrite" entries.
+ * It has following fields.
+ *
+ *  (1) "list" which is linked to tomoyo_no_rewrite_list .
+ *  (2) "pattern" is a pathname which is by default not permitted to modify
+ *      already existing content.
+ *  (3) "is_deleted" is a bool which is true if marked as deleted, false
+ *      otherwise.
+ */
 struct tomoyo_no_rewrite_entry {
        struct list_head list;
        const struct tomoyo_path_info *pattern;
@@ -141,7 +170,31 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
                                         struct tomoyo_domain_info *
                                         const domain, const bool is_delete);
 
-/* The list for "struct tomoyo_globally_readable_file_entry". */
+/*
+ * tomoyo_globally_readable_list is used for holding list of pathnames which
+ * are by default allowed to be open()ed for reading by any process.
+ *
+ * An entry is added by
+ *
+ * # echo 'allow_read /lib/libc-2.5.so' > \
+ *                               /sys/kernel/security/tomoyo/exception_policy
+ *
+ * and is deleted by
+ *
+ * # echo 'delete allow_read /lib/libc-2.5.so' > \
+ *                               /sys/kernel/security/tomoyo/exception_policy
+ *
+ * and all entries are retrieved by
+ *
+ * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy
+ *
+ * In the example above, any process is allowed to
+ * open("/lib/libc-2.5.so", O_RDONLY).
+ * One exception is, if the domain which current process belongs to is marked
+ * as "ignore_global_allow_read", current process can't do so unless explicitly
+ * given "allow_read /lib/libc-2.5.so" to the domain which current process
+ * belongs to.
+ */
 static LIST_HEAD(tomoyo_globally_readable_list);
 static DECLARE_RWSEM(tomoyo_globally_readable_list_lock);
 
@@ -166,7 +219,6 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
        saved_filename = tomoyo_save_name(filename);
        if (!saved_filename)
                return -ENOMEM;
-       /***** EXCLUSIVE SECTION START *****/
        down_write(&tomoyo_globally_readable_list_lock);
        list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
                if (ptr->filename != saved_filename)
@@ -187,7 +239,6 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
        error = 0;
  out:
        up_write(&tomoyo_globally_readable_list_lock);
-       /***** EXCLUSIVE SECTION END *****/
        return error;
 }
 
@@ -249,17 +300,44 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
                                 list);
                if (ptr->is_deleted)
                        continue;
-               if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n",
-                                     ptr->filename->name)) {
-                       done = false;
+               done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n",
+                                       ptr->filename->name);
+               if (!done)
                        break;
-               }
        }
        up_read(&tomoyo_globally_readable_list_lock);
        return done;
 }
 
-/* The list for "struct tomoyo_pattern_entry". */
+/* tomoyo_pattern_list is used for holding list of pathnames which are used for
+ * converting pathnames to pathname patterns during learning mode.
+ *
+ * An entry is added by
+ *
+ * # echo 'file_pattern /proc/\$/mounts' > \
+ *                             /sys/kernel/security/tomoyo/exception_policy
+ *
+ * and is deleted by
+ *
+ * # echo 'delete file_pattern /proc/\$/mounts' > \
+ *                             /sys/kernel/security/tomoyo/exception_policy
+ *
+ * and all entries are retrieved by
+ *
+ * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy
+ *
+ * In the example above, if a process which belongs to a domain which is in
+ * learning mode requested open("/proc/1/mounts", O_RDONLY),
+ * "allow_read /proc/\$/mounts" is automatically added to the domain which that
+ * process belongs to.
+ *
+ * It is not a desirable behavior that we have to use /proc/\$/ instead of
+ * /proc/self/ when current process needs to access only current process's
+ * information. As of now, LSM version of TOMOYO is using __d_path() for
+ * calculating pathname. Non LSM version of TOMOYO is using its own function
+ * which pretends as if /proc/self/ is not a symlink; so that we can forbid
+ * current process from accessing other process's information.
+ */
 static LIST_HEAD(tomoyo_pattern_list);
 static DECLARE_RWSEM(tomoyo_pattern_list_lock);
 
@@ -284,7 +362,6 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
        saved_pattern = tomoyo_save_name(pattern);
        if (!saved_pattern)
                return -ENOMEM;
-       /***** EXCLUSIVE SECTION START *****/
        down_write(&tomoyo_pattern_list_lock);
        list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
                if (saved_pattern != ptr->pattern)
@@ -305,7 +382,6 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
        error = 0;
  out:
        up_write(&tomoyo_pattern_list_lock);
-       /***** EXCLUSIVE SECTION END *****/
        return error;
 }
 
@@ -373,17 +449,44 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
                ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
                if (ptr->is_deleted)
                        continue;
-               if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN "%s\n",
-                                     ptr->pattern->name)) {
-                       done = false;
+               done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN
+                                       "%s\n", ptr->pattern->name);
+               if (!done)
                        break;
-               }
        }
        up_read(&tomoyo_pattern_list_lock);
        return done;
 }
 
-/* The list for "struct tomoyo_no_rewrite_entry". */
+/*
+ * tomoyo_no_rewrite_list is used for holding list of pathnames which are by
+ * default forbidden to modify already written content of a file.
+ *
+ * An entry is added by
+ *
+ * # echo 'deny_rewrite /var/log/messages' > \
+ *                              /sys/kernel/security/tomoyo/exception_policy
+ *
+ * and is deleted by
+ *
+ * # echo 'delete deny_rewrite /var/log/messages' > \
+ *                              /sys/kernel/security/tomoyo/exception_policy
+ *
+ * and all entries are retrieved by
+ *
+ * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy
+ *
+ * In the example above, if a process requested to rewrite /var/log/messages ,
+ * the process can't rewrite unless the domain which that process belongs to
+ * has "allow_rewrite /var/log/messages" entry.
+ *
+ * It is not a desirable behavior that we have to add "\040(deleted)" suffix
+ * when we want to allow rewriting already unlink()ed file. As of now,
+ * LSM version of TOMOYO is using __d_path() for calculating pathname.
+ * Non LSM version of TOMOYO is using its own function which doesn't append
+ * " (deleted)" suffix if the file is already unlink()ed; so that we don't
+ * need to worry whether the file is already unlink()ed or not.
+ */
 static LIST_HEAD(tomoyo_no_rewrite_list);
 static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock);
 
@@ -407,7 +510,6 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
        saved_pattern = tomoyo_save_name(pattern);
        if (!saved_pattern)
                return -ENOMEM;
-       /***** EXCLUSIVE SECTION START *****/
        down_write(&tomoyo_no_rewrite_list_lock);
        list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
                if (ptr->pattern != saved_pattern)
@@ -428,7 +530,6 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
        error = 0;
  out:
        up_write(&tomoyo_no_rewrite_list_lock);
-       /***** EXCLUSIVE SECTION END *****/
        return error;
 }
 
@@ -489,11 +590,10 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
                ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
                if (ptr->is_deleted)
                        continue;
-               if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE "%s\n",
-                                     ptr->pattern->name)) {
-                       done = false;
+               done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE
+                                       "%s\n", ptr->pattern->name);
+               if (!done)
                        break;
-               }
        }
        up_read(&tomoyo_no_rewrite_list_lock);
        return done;
@@ -745,7 +845,6 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
        saved_filename = tomoyo_save_name(filename);
        if (!saved_filename)
                return -ENOMEM;
-       /***** EXCLUSIVE SECTION START *****/
        down_write(&tomoyo_domain_acl_info_list_lock);
        if (is_delete)
                goto delete;
@@ -800,7 +899,6 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
        }
  out:
        up_write(&tomoyo_domain_acl_info_list_lock);
-       /***** EXCLUSIVE SECTION END *****/
        return error;
 }
 
@@ -836,7 +934,6 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
        saved_filename2 = tomoyo_save_name(filename2);
        if (!saved_filename1 || !saved_filename2)
                return -ENOMEM;
-       /***** EXCLUSIVE SECTION START *****/
        down_write(&tomoyo_domain_acl_info_list_lock);
        if (is_delete)
                goto delete;
@@ -884,7 +981,6 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
        }
  out:
        up_write(&tomoyo_domain_acl_info_list_lock);
-       /***** EXCLUSIVE SECTION END *****/
        return error;
 }
 
@@ -1025,13 +1121,11 @@ int tomoyo_check_file_perm(struct tomoyo_domain_info *domain,
  *
  * @domain:   Pointer to "struct tomoyo_domain_info".
  * @filename: Check permission for "execute".
- * @tmp:      Buffer for temporary use.
  *
  * Returns 0 on success, negativevalue otherwise.
  */
 int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
-                          const struct tomoyo_path_info *filename,
-                          struct tomoyo_page_buffer *tmp)
+                          const struct tomoyo_path_info *filename)
 {
        const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
 
index 40927a84cb6e697a24671c36a3527c1645f850a1..5f2e3326337118c9252dc80ec10e53b3365c0a9c 100644 (file)
@@ -220,7 +220,6 @@ void *tomoyo_alloc_element(const unsigned int size)
                = roundup(size, max(sizeof(void *), sizeof(long)));
        if (word_aligned_size > PATH_MAX)
                return NULL;
-       /***** EXCLUSIVE SECTION START *****/
        mutex_lock(&lock);
        if (buf_used_len + word_aligned_size > PATH_MAX) {
                if (!tomoyo_quota_for_elements ||
@@ -251,7 +250,6 @@ void *tomoyo_alloc_element(const unsigned int size)
                }
        }
        mutex_unlock(&lock);
-       /***** EXCLUSIVE SECTION END *****/
        return ptr;
 }
 
@@ -267,7 +265,16 @@ static unsigned int tomoyo_quota_for_savename;
  */
 #define TOMOYO_MAX_HASH 256
 
-/* Structure for string data. */
+/*
+ * tomoyo_name_entry is a structure which is used for linking
+ * "struct tomoyo_path_info" into tomoyo_name_list .
+ *
+ * Since tomoyo_name_list manages a list of strings which are shared by
+ * multiple processes (whereas "struct tomoyo_path_info" inside
+ * "struct tomoyo_path_info_with_data" is not shared), a reference counter will
+ * be added to "struct tomoyo_name_entry" rather than "struct tomoyo_path_info"
+ * when TOMOYO starts supporting garbage collector.
+ */
 struct tomoyo_name_entry {
        struct list_head list;
        struct tomoyo_path_info entry;
@@ -281,10 +288,10 @@ struct tomoyo_free_memory_block_list {
 };
 
 /*
- * The list for "struct tomoyo_name_entry".
- *
- * This list is updated only inside tomoyo_save_name(), thus
- * no global mutex exists.
+ * tomoyo_name_list is used for holding string data used by TOMOYO.
+ * Since same string data is likely used for multiple times (e.g.
+ * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of
+ * "const struct tomoyo_path_info *".
  */
 static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
 
@@ -318,7 +325,6 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name)
                return NULL;
        }
        hash = full_name_hash((const unsigned char *) name, len - 1);
-       /***** EXCLUSIVE SECTION START *****/
        mutex_lock(&lock);
        list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH],
                             list) {
@@ -366,7 +372,6 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name)
        }
  out:
        mutex_unlock(&lock);
-       /***** EXCLUSIVE SECTION END *****/
        return ptr ? &ptr->entry : NULL;
 }
 
index e42be5c4f055b5ebb5258fdb3e6d041f9b3d2f91..3194d09fe0f4ccd5311b819e526a1b696a8ecc33 100644 (file)
@@ -262,6 +262,10 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
        return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags);
 }
 
+/*
+ * tomoyo_security_ops is a "struct security_operations" which is used for
+ * registering TOMOYO.
+ */
 static struct security_operations tomoyo_security_ops = {
        .name                = "tomoyo",
        .cred_prepare        = tomoyo_cred_prepare,
index 41c6ebafb9c561ad203cc52cef886378e01309e7..0fd588a629cf915ca6be0a47dbc300292d908570 100644 (file)
@@ -17,13 +17,11 @@ struct path;
 struct inode;
 struct linux_binprm;
 struct pt_regs;
-struct tomoyo_page_buffer;
 
 int tomoyo_check_file_perm(struct tomoyo_domain_info *domain,
                           const char *filename, const u8 perm);
 int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
-                          const struct tomoyo_path_info *filename,
-                          struct tomoyo_page_buffer *buf);
+                          const struct tomoyo_path_info *filename);
 int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
                                 struct path *path, const int flag);
 int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
@@ -90,17 +88,10 @@ static inline struct tomoyo_domain_info *tomoyo_domain(void)
        return current_cred()->security;
 }
 
-/* Caller holds tasklist_lock spinlock. */
 static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
                                                            *task)
 {
-       /***** CRITICAL SECTION START *****/
-       const struct cred *cred = get_task_cred(task);
-       struct tomoyo_domain_info *domain = cred->security;
-
-       put_cred(cred);
-       return domain;
-       /***** CRITICAL SECTION END *****/
+       return task_cred_xxx(task, security);
 }
 
 #endif /* !defined(_SECURITY_TOMOYO_TOMOYO_H) */
index 1ca7427c4b6d869d48a19382c60949620ab178d1..bcf2a0698d5453b1c7a2bdf18f8a63bf14f1ea91 100644 (file)
@@ -561,7 +561,7 @@ endif       # SOUND_OSS
 
 config SOUND_SH_DAC_AUDIO
        tristate "SuperH DAC audio support"
-       depends on CPU_SH3
+       depends on CPU_SH3 && HIGH_RES_TIMERS
 
 config SOUND_SH_DAC_AUDIO_CHANNEL
        int "DAC channel"
index 78cfb66e4c59cecf83c51d55b8b7f7baf9bf683b..b2ed8757542ac50fd49f88557118bbb703c88c04 100644 (file)
 #include <linux/sound.h>
 #include <linux/soundcard.h>
 #include <linux/interrupt.h>
+#include <linux/hrtimer.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/irq.h>
 #include <asm/delay.h>
 #include <asm/clock.h>
-#include <asm/cpu/dac.h>
-#include <asm/cpu/timer.h>
+#include <cpu/dac.h>
 #include <asm/machvec.h>
 #include <mach/hp6xx.h>
 #include <asm/hd64461.h>
 
 #define MODNAME "sh_dac_audio"
 
-#define TMU_TOCR_INIT  0x00
-
-#define TMU1_TCR_INIT  0x0020  /* Clock/4, rising edge; interrupt on */
-#define TMU1_TSTR_INIT  0x02   /* Bit to turn on TMU1 */
-
 #define BUFFER_SIZE 48000
 
 static int rate;
 static int empty;
 static char *data_buffer, *buffer_begin, *buffer_end;
 static int in_use, device_major;
+static struct hrtimer hrtimer;
+static ktime_t wakeups_per_second;
 
 static void dac_audio_start_timer(void)
 {
-       u8 tstr;
-
-       tstr = ctrl_inb(TMU_TSTR);
-       tstr |= TMU1_TSTR_INIT;
-       ctrl_outb(tstr, TMU_TSTR);
+       hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
 }
 
 static void dac_audio_stop_timer(void)
 {
-       u8 tstr;
-
-       tstr = ctrl_inb(TMU_TSTR);
-       tstr &= ~TMU1_TSTR_INIT;
-       ctrl_outb(tstr, TMU_TSTR);
+       hrtimer_cancel(&hrtimer);
 }
 
 static void dac_audio_reset(void)
@@ -77,38 +66,30 @@ static void dac_audio_sync(void)
 static void dac_audio_start(void)
 {
        if (mach_is_hp6xx()) {
-               u16 v = inw(HD64461_GPADR);
+               u16 v = __raw_readw(HD64461_GPADR);
                v &= ~HD64461_GPADR_SPEAKER;
-               outw(v, HD64461_GPADR);
+               __raw_writew(v, HD64461_GPADR);
        }
 
        sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-       ctrl_outw(TMU1_TCR_INIT, TMU1_TCR);
 }
 static void dac_audio_stop(void)
 {
        dac_audio_stop_timer();
 
        if (mach_is_hp6xx()) {
-               u16 v = inw(HD64461_GPADR);
+               u16 v = __raw_readw(HD64461_GPADR);
                v |= HD64461_GPADR_SPEAKER;
-               outw(v, HD64461_GPADR);
+               __raw_writew(v, HD64461_GPADR);
        }
 
-       sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
+       sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
        sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
 }
 
 static void dac_audio_set_rate(void)
 {
-       unsigned long interval;
-       struct clk *clk;
-
-       clk = clk_get(NULL, "module_clk");
-       interval = (clk_get_rate(clk) / 4) / rate;
-       clk_put(clk);
-       ctrl_outl(interval, TMU1_TCOR);
-       ctrl_outl(interval, TMU1_TCNT);
+       wakeups_per_second = ktime_set(0, 1000000000 / rate);
 }
 
 static int dac_audio_ioctl(struct inode *inode, struct file *file,
@@ -265,32 +246,26 @@ const struct file_operations dac_audio_fops = {
       .release =       dac_audio_release,
 };
 
-static irqreturn_t timer1_interrupt(int irq, void *dev)
+static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle)
 {
-       unsigned long timer_status;
-
-       timer_status = ctrl_inw(TMU1_TCR);
-       timer_status &= ~0x100;
-       ctrl_outw(timer_status, TMU1_TCR);
-
        if (!empty) {
                sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
                buffer_begin++;
 
                if (buffer_begin == data_buffer + BUFFER_SIZE)
                        buffer_begin = data_buffer;
-               if (buffer_begin == buffer_end) {
+               if (buffer_begin == buffer_end)
                        empty = 1;
-                       dac_audio_stop_timer();
-               }
        }
-       return IRQ_HANDLED;
+
+       if (!empty)
+               hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
+
+       return HRTIMER_NORESTART;
 }
 
 static int __init dac_audio_init(void)
 {
-       int retval;
-
        if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) {
                printk(KERN_ERR "Cannot register dsp device");
                return device_major;
@@ -306,21 +281,25 @@ static int __init dac_audio_init(void)
        rate = 8000;
        dac_audio_set_rate();
 
-       retval =
-           request_irq(TIMER1_IRQ, timer1_interrupt, IRQF_DISABLED, MODNAME, 0);
-       if (retval < 0) {
-               printk(KERN_ERR "sh_dac_audio: IRQ %d request failed\n",
-                      TIMER1_IRQ);
-               return retval;
-       }
+       /* Today: High Resolution Timer driven DAC playback.
+        * The timer callback gets called once per sample. Ouch.
+        *
+        * Future: A much better approach would be to use the
+        * SH7720 CMT+DMAC+DAC hardware combination like this:
+        * - Program sample rate using CMT0 or CMT1
+        * - Program DMAC to use CMT for timing and output to DAC
+        * - Play sound using DMAC, let CPU sleep.
+        * - While at it, rewrite this driver to use ALSA.
+        */
+
+       hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       hrtimer.function = sh_dac_audio_timer;
 
        return 0;
 }
 
 static void __exit dac_audio_exit(void)
 {
-       free_irq(TIMER1_IRQ, 0);
-
        unregister_sound_dsp(device_major);
        kfree((void *)data_buffer);
 }
index c3b99def9cbc3c1eff063248a064d7ee3fc8c84e..1eddae94bab331bee8eb01b5e71fd6df8e0d7604 100644 (file)
@@ -85,7 +85,7 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
 
 static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
 {
-       union ioapic_redir_entry *pent;
+       union kvm_ioapic_redirect_entry *pent;
        int injected = -1;
 
        pent = &ioapic->redirtbl[idx];
@@ -142,149 +142,40 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
        }
 }
 
-static int ioapic_inj_irq(struct kvm_ioapic *ioapic,
-                          struct kvm_vcpu *vcpu,
-                          u8 vector, u8 trig_mode, u8 delivery_mode)
-{
-       ioapic_debug("irq %d trig %d deliv %d\n", vector, trig_mode,
-                    delivery_mode);
-
-       ASSERT((delivery_mode == IOAPIC_FIXED) ||
-              (delivery_mode == IOAPIC_LOWEST_PRIORITY));
-
-       return kvm_apic_set_irq(vcpu, vector, trig_mode);
-}
-
-static void ioapic_inj_nmi(struct kvm_vcpu *vcpu)
-{
-       kvm_inject_nmi(vcpu);
-       kvm_vcpu_kick(vcpu);
-}
-
-u32 kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
-                                   u8 dest_mode)
-{
-       u32 mask = 0;
-       int i;
-       struct kvm *kvm = ioapic->kvm;
-       struct kvm_vcpu *vcpu;
-
-       ioapic_debug("dest %d dest_mode %d\n", dest, dest_mode);
-
-       if (dest_mode == 0) {   /* Physical mode. */
-               if (dest == 0xFF) {     /* Broadcast. */
-                       for (i = 0; i < KVM_MAX_VCPUS; ++i)
-                               if (kvm->vcpus[i] && kvm->vcpus[i]->arch.apic)
-                                       mask |= 1 << i;
-                       return mask;
-               }
-               for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-                       vcpu = kvm->vcpus[i];
-                       if (!vcpu)
-                               continue;
-                       if (kvm_apic_match_physical_addr(vcpu->arch.apic, dest)) {
-                               if (vcpu->arch.apic)
-                                       mask = 1 << i;
-                               break;
-                       }
-               }
-       } else if (dest != 0)   /* Logical mode, MDA non-zero. */
-               for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-                       vcpu = kvm->vcpus[i];
-                       if (!vcpu)
-                               continue;
-                       if (vcpu->arch.apic &&
-                           kvm_apic_match_logical_addr(vcpu->arch.apic, dest))
-                               mask |= 1 << vcpu->vcpu_id;
-               }
-       ioapic_debug("mask %x\n", mask);
-       return mask;
-}
-
 static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
 {
-       u8 dest = ioapic->redirtbl[irq].fields.dest_id;
-       u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode;
-       u8 delivery_mode = ioapic->redirtbl[irq].fields.delivery_mode;
-       u8 vector = ioapic->redirtbl[irq].fields.vector;
-       u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode;
-       u32 deliver_bitmask;
-       struct kvm_vcpu *vcpu;
-       int vcpu_id, r = -1;
+       union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq];
+       struct kvm_lapic_irq irqe;
 
        ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
                     "vector=%x trig_mode=%x\n",
-                    dest, dest_mode, delivery_mode, vector, trig_mode);
-
-       deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic, dest,
-                                                         dest_mode);
-       if (!deliver_bitmask) {
-               ioapic_debug("no target on destination\n");
-               return 0;
-       }
+                    entry->fields.dest, entry->fields.dest_mode,
+                    entry->fields.delivery_mode, entry->fields.vector,
+                    entry->fields.trig_mode);
+
+       irqe.dest_id = entry->fields.dest_id;
+       irqe.vector = entry->fields.vector;
+       irqe.dest_mode = entry->fields.dest_mode;
+       irqe.trig_mode = entry->fields.trig_mode;
+       irqe.delivery_mode = entry->fields.delivery_mode << 8;
+       irqe.level = 1;
+       irqe.shorthand = 0;
 
-       switch (delivery_mode) {
-       case IOAPIC_LOWEST_PRIORITY:
-               vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, vector,
-                               deliver_bitmask);
 #ifdef CONFIG_X86
-               if (irq == 0)
-                       vcpu = ioapic->kvm->vcpus[0];
-#endif
-               if (vcpu != NULL)
-                       r = ioapic_inj_irq(ioapic, vcpu, vector,
-                                      trig_mode, delivery_mode);
-               else
-                       ioapic_debug("null lowest prio vcpu: "
-                                    "mask=%x vector=%x delivery_mode=%x\n",
-                                    deliver_bitmask, vector, IOAPIC_LOWEST_PRIORITY);
-               break;
-       case IOAPIC_FIXED:
-#ifdef CONFIG_X86
-               if (irq == 0)
-                       deliver_bitmask = 1;
-#endif
-               for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
-                       if (!(deliver_bitmask & (1 << vcpu_id)))
-                               continue;
-                       deliver_bitmask &= ~(1 << vcpu_id);
-                       vcpu = ioapic->kvm->vcpus[vcpu_id];
-                       if (vcpu) {
-                               if (r < 0)
-                                       r = 0;
-                               r += ioapic_inj_irq(ioapic, vcpu, vector,
-                                              trig_mode, delivery_mode);
-                       }
-               }
-               break;
-       case IOAPIC_NMI:
-               for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
-                       if (!(deliver_bitmask & (1 << vcpu_id)))
-                               continue;
-                       deliver_bitmask &= ~(1 << vcpu_id);
-                       vcpu = ioapic->kvm->vcpus[vcpu_id];
-                       if (vcpu) {
-                               ioapic_inj_nmi(vcpu);
-                               r = 1;
-                       }
-                       else
-                               ioapic_debug("NMI to vcpu %d failed\n",
-                                               vcpu->vcpu_id);
-               }
-               break;
-       default:
-               printk(KERN_WARNING "Unsupported delivery mode %d\n",
-                      delivery_mode);
-               break;
+       /* Always delivery PIT interrupt to vcpu 0 */
+       if (irq == 0) {
+               irqe.dest_mode = 0; /* Physical mode. */
+               irqe.dest_id = ioapic->kvm->vcpus[0]->vcpu_id;
        }
-       return r;
+#endif
+       return kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe);
 }
 
 int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
 {
        u32 old_irr = ioapic->irr;
        u32 mask = 1 << irq;
-       union ioapic_redir_entry entry;
+       union kvm_ioapic_redirect_entry entry;
        int ret = 1;
 
        if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
@@ -305,7 +196,7 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
 static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int pin,
                                    int trigger_mode)
 {
-       union ioapic_redir_entry *ent;
+       union kvm_ioapic_redirect_entry *ent;
 
        ent = &ioapic->redirtbl[pin];
 
index a34bd5e6436bddf086f4e7dca13bdce09776fa64..7080b713c160310788f6f61baa446fda9bf29a23 100644 (file)
@@ -40,22 +40,7 @@ struct kvm_ioapic {
        u32 id;
        u32 irr;
        u32 pad;
-       union ioapic_redir_entry {
-               u64 bits;
-               struct {
-                       u8 vector;
-                       u8 delivery_mode:3;
-                       u8 dest_mode:1;
-                       u8 delivery_status:1;
-                       u8 polarity:1;
-                       u8 remote_irr:1;
-                       u8 trig_mode:1;
-                       u8 mask:1;
-                       u8 reserve:7;
-                       u8 reserved[4];
-                       u8 dest_id;
-               } fields;
-       } redirtbl[IOAPIC_NUM_PINS];
+       union kvm_ioapic_redirect_entry redirtbl[IOAPIC_NUM_PINS];
        struct kvm_io_device dev;
        struct kvm *kvm;
        void (*ack_notifier)(void *opaque, int irq);
@@ -79,13 +64,13 @@ static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm)
        return kvm->arch.vioapic;
 }
 
-struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
-                                      unsigned long bitmap);
+int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
+               int short_hand, int dest, int dest_mode);
+int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2);
 void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
 int kvm_ioapic_init(struct kvm *kvm);
 int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
 void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
-u32 kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
-                               u8 dest_mode);
-
+int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
+               struct kvm_lapic_irq *irq);
 #endif
index 4c403750360082f0e53d3e5459c17d78797ab9e0..15147583abd164d64de465eb7fce9d0c27a41ef8 100644 (file)
@@ -39,11 +39,16 @@ int kvm_iommu_map_pages(struct kvm *kvm,
        pfn_t pfn;
        int i, r = 0;
        struct iommu_domain *domain = kvm->arch.iommu_domain;
+       int flags;
 
        /* check if iommu exists and in use */
        if (!domain)
                return 0;
 
+       flags = IOMMU_READ | IOMMU_WRITE;
+       if (kvm->arch.iommu_flags & KVM_IOMMU_CACHE_COHERENCY)
+               flags |= IOMMU_CACHE;
+
        for (i = 0; i < npages; i++) {
                /* check if already mapped */
                if (iommu_iova_to_phys(domain, gfn_to_gpa(gfn)))
@@ -53,8 +58,7 @@ int kvm_iommu_map_pages(struct kvm *kvm,
                r = iommu_map_range(domain,
                                    gfn_to_gpa(gfn),
                                    pfn_to_hpa(pfn),
-                                   PAGE_SIZE,
-                                   IOMMU_READ | IOMMU_WRITE);
+                                   PAGE_SIZE, flags);
                if (r) {
                        printk(KERN_ERR "kvm_iommu_map_address:"
                               "iommu failed to map pfn=%lx\n", pfn);
@@ -88,7 +92,7 @@ int kvm_assign_device(struct kvm *kvm,
 {
        struct pci_dev *pdev = NULL;
        struct iommu_domain *domain = kvm->arch.iommu_domain;
-       int r;
+       int r, last_flags;
 
        /* check if iommu exists and in use */
        if (!domain)
@@ -107,12 +111,29 @@ int kvm_assign_device(struct kvm *kvm,
                return r;
        }
 
+       last_flags = kvm->arch.iommu_flags;
+       if (iommu_domain_has_cap(kvm->arch.iommu_domain,
+                                IOMMU_CAP_CACHE_COHERENCY))
+               kvm->arch.iommu_flags |= KVM_IOMMU_CACHE_COHERENCY;
+
+       /* Check if need to update IOMMU page table for guest memory */
+       if ((last_flags ^ kvm->arch.iommu_flags) ==
+                       KVM_IOMMU_CACHE_COHERENCY) {
+               kvm_iommu_unmap_memslots(kvm);
+               r = kvm_iommu_map_memslots(kvm);
+               if (r)
+                       goto out_unmap;
+       }
+
        printk(KERN_DEBUG "assign device: host bdf = %x:%x:%x\n",
                assigned_dev->host_busnr,
                PCI_SLOT(assigned_dev->host_devfn),
                PCI_FUNC(assigned_dev->host_devfn));
 
        return 0;
+out_unmap:
+       kvm_iommu_unmap_memslots(kvm);
+       return r;
 }
 
 int kvm_deassign_device(struct kvm *kvm,
index 864ac5483baade3fce7085c3c51f23e493426914..a8bd466d00ccf1af71ab09e229197c2366fcdef5 100644 (file)
@@ -22,6 +22,9 @@
 #include <linux/kvm_host.h>
 
 #include <asm/msidef.h>
+#ifdef CONFIG_IA64
+#include <asm/iosapic.h>
+#endif
 
 #include "irq.h"
 
@@ -43,57 +46,73 @@ static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
        return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level);
 }
 
-static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
-                      struct kvm *kvm, int level)
+inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq)
 {
-       int vcpu_id, r = -1;
-       struct kvm_vcpu *vcpu;
-       struct kvm_ioapic *ioapic = ioapic_irqchip(kvm);
-       int dest_id = (e->msi.address_lo & MSI_ADDR_DEST_ID_MASK)
-                       >> MSI_ADDR_DEST_ID_SHIFT;
-       int vector = (e->msi.data & MSI_DATA_VECTOR_MASK)
-                       >> MSI_DATA_VECTOR_SHIFT;
-       int dest_mode = test_bit(MSI_ADDR_DEST_MODE_SHIFT,
-                               (unsigned long *)&e->msi.address_lo);
-       int trig_mode = test_bit(MSI_DATA_TRIGGER_SHIFT,
-                               (unsigned long *)&e->msi.data);
-       int delivery_mode = test_bit(MSI_DATA_DELIVERY_MODE_SHIFT,
-                               (unsigned long *)&e->msi.data);
-       u32 deliver_bitmask;
-
-       BUG_ON(!ioapic);
-
-       deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic,
-                               dest_id, dest_mode);
-       /* IOAPIC delivery mode value is the same as MSI here */
-       switch (delivery_mode) {
-       case IOAPIC_LOWEST_PRIORITY:
-               vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, vector,
-                               deliver_bitmask);
-               if (vcpu != NULL)
-                       r = kvm_apic_set_irq(vcpu, vector, trig_mode);
-               else
-                       printk(KERN_INFO "kvm: null lowest priority vcpu!\n");
-               break;
-       case IOAPIC_FIXED:
-               for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
-                       if (!(deliver_bitmask & (1 << vcpu_id)))
-                               continue;
-                       deliver_bitmask &= ~(1 << vcpu_id);
-                       vcpu = ioapic->kvm->vcpus[vcpu_id];
-                       if (vcpu) {
-                               if (r < 0)
-                                       r = 0;
-                               r += kvm_apic_set_irq(vcpu, vector, trig_mode);
-                       }
+#ifdef CONFIG_IA64
+       return irq->delivery_mode ==
+               (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
+#else
+       return irq->delivery_mode == APIC_DM_LOWEST;
+#endif
+}
+
+int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
+               struct kvm_lapic_irq *irq)
+{
+       int i, r = -1;
+       struct kvm_vcpu *vcpu, *lowest = NULL;
+
+       if (irq->dest_mode == 0 && irq->dest_id == 0xff &&
+                       kvm_is_dm_lowest_prio(irq))
+               printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n");
+
+       for (i = 0; i < KVM_MAX_VCPUS; i++) {
+               vcpu = kvm->vcpus[i];
+
+               if (!vcpu || !kvm_apic_present(vcpu))
+                       continue;
+
+               if (!kvm_apic_match_dest(vcpu, src, irq->shorthand,
+                                       irq->dest_id, irq->dest_mode))
+                       continue;
+
+               if (!kvm_is_dm_lowest_prio(irq)) {
+                       if (r < 0)
+                               r = 0;
+                       r += kvm_apic_set_irq(vcpu, irq);
+               } else {
+                       if (!lowest)
+                               lowest = vcpu;
+                       else if (kvm_apic_compare_prio(vcpu, lowest) < 0)
+                               lowest = vcpu;
                }
-               break;
-       default:
-               break;
        }
+
+       if (lowest)
+               r = kvm_apic_set_irq(lowest, irq);
+
        return r;
 }
 
+static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
+                      struct kvm *kvm, int level)
+{
+       struct kvm_lapic_irq irq;
+
+       irq.dest_id = (e->msi.address_lo &
+                       MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
+       irq.vector = (e->msi.data &
+                       MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
+       irq.dest_mode = (1 << MSI_ADDR_DEST_MODE_SHIFT) & e->msi.address_lo;
+       irq.trig_mode = (1 << MSI_DATA_TRIGGER_SHIFT) & e->msi.data;
+       irq.delivery_mode = e->msi.data & 0x700;
+       irq.level = 1;
+       irq.shorthand = 0;
+
+       /* TODO Deal with RH bit of MSI message address */
+       return kvm_irq_delivery_to_apic(kvm, NULL, &irq);
+}
+
 /* This should be called with the kvm->lock mutex held
  * Return value:
  *  < 0   Interrupt was ignored (masked or not delivered for other reasons)
@@ -252,7 +271,7 @@ static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e,
                        delta = 8;
                        break;
                case KVM_IRQCHIP_IOAPIC:
-                               e->set = kvm_set_ioapic_irq;
+                       e->set = kvm_set_ioapic_irq;
                        break;
                default:
                        goto out;
index 4d0dd390aa50129a99df9c13d3643a96ff0bfd50..e21194566b7140b423d9d438e433f737256681bb 100644 (file)
@@ -41,6 +41,8 @@
 #include <linux/pagemap.h>
 #include <linux/mman.h>
 #include <linux/swap.h>
+#include <linux/bitops.h>
+#include <linux/spinlock.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
@@ -60,9 +62,6 @@
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
-static int msi2intx = 1;
-module_param(msi2intx, bool, 0);
-
 DEFINE_SPINLOCK(kvm_lock);
 LIST_HEAD(vm_list);
 
@@ -95,38 +94,96 @@ static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *h
        return NULL;
 }
 
+static int find_index_from_host_irq(struct kvm_assigned_dev_kernel
+                                   *assigned_dev, int irq)
+{
+       int i, index;
+       struct msix_entry *host_msix_entries;
+
+       host_msix_entries = assigned_dev->host_msix_entries;
+
+       index = -1;
+       for (i = 0; i < assigned_dev->entries_nr; i++)
+               if (irq == host_msix_entries[i].vector) {
+                       index = i;
+                       break;
+               }
+       if (index < 0) {
+               printk(KERN_WARNING "Fail to find correlated MSI-X entry!\n");
+               return 0;
+       }
+
+       return index;
+}
+
 static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
 {
        struct kvm_assigned_dev_kernel *assigned_dev;
+       struct kvm *kvm;
+       int irq, i;
 
        assigned_dev = container_of(work, struct kvm_assigned_dev_kernel,
                                    interrupt_work);
+       kvm = assigned_dev->kvm;
 
        /* This is taken to safely inject irq inside the guest. When
         * the interrupt injection (or the ioapic code) uses a
         * finer-grained lock, update this
         */
-       mutex_lock(&assigned_dev->kvm->lock);
-       kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
-                   assigned_dev->guest_irq, 1);
-
-       if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_MSI) {
-               enable_irq(assigned_dev->host_irq);
-               assigned_dev->host_irq_disabled = false;
+       mutex_lock(&kvm->lock);
+       spin_lock_irq(&assigned_dev->assigned_dev_lock);
+       if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
+               struct kvm_guest_msix_entry *guest_entries =
+                       assigned_dev->guest_msix_entries;
+               for (i = 0; i < assigned_dev->entries_nr; i++) {
+                       if (!(guest_entries[i].flags &
+                                       KVM_ASSIGNED_MSIX_PENDING))
+                               continue;
+                       guest_entries[i].flags &= ~KVM_ASSIGNED_MSIX_PENDING;
+                       kvm_set_irq(assigned_dev->kvm,
+                                   assigned_dev->irq_source_id,
+                                   guest_entries[i].vector, 1);
+                       irq = assigned_dev->host_msix_entries[i].vector;
+                       if (irq != 0)
+                               enable_irq(irq);
+                       assigned_dev->host_irq_disabled = false;
+               }
+       } else {
+               kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
+                           assigned_dev->guest_irq, 1);
+               if (assigned_dev->irq_requested_type &
+                               KVM_DEV_IRQ_GUEST_MSI) {
+                       enable_irq(assigned_dev->host_irq);
+                       assigned_dev->host_irq_disabled = false;
+               }
        }
+
+       spin_unlock_irq(&assigned_dev->assigned_dev_lock);
        mutex_unlock(&assigned_dev->kvm->lock);
 }
 
 static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
 {
+       unsigned long flags;
        struct kvm_assigned_dev_kernel *assigned_dev =
                (struct kvm_assigned_dev_kernel *) dev_id;
 
+       spin_lock_irqsave(&assigned_dev->assigned_dev_lock, flags);
+       if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
+               int index = find_index_from_host_irq(assigned_dev, irq);
+               if (index < 0)
+                       goto out;
+               assigned_dev->guest_msix_entries[index].flags |=
+                       KVM_ASSIGNED_MSIX_PENDING;
+       }
+
        schedule_work(&assigned_dev->interrupt_work);
 
        disable_irq_nosync(irq);
        assigned_dev->host_irq_disabled = true;
 
+out:
+       spin_unlock_irqrestore(&assigned_dev->assigned_dev_lock, flags);
        return IRQ_HANDLED;
 }
 
@@ -134,6 +191,7 @@ static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
 static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
 {
        struct kvm_assigned_dev_kernel *dev;
+       unsigned long flags;
 
        if (kian->gsi == -1)
                return;
@@ -146,28 +204,30 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
        /* The guest irq may be shared so this ack may be
         * from another device.
         */
+       spin_lock_irqsave(&dev->assigned_dev_lock, flags);
        if (dev->host_irq_disabled) {
                enable_irq(dev->host_irq);
                dev->host_irq_disabled = false;
        }
+       spin_unlock_irqrestore(&dev->assigned_dev_lock, flags);
 }
 
-/* The function implicit hold kvm->lock mutex due to cancel_work_sync() */
-static void kvm_free_assigned_irq(struct kvm *kvm,
-                                 struct kvm_assigned_dev_kernel *assigned_dev)
+static void deassign_guest_irq(struct kvm *kvm,
+                              struct kvm_assigned_dev_kernel *assigned_dev)
 {
-       if (!irqchip_in_kernel(kvm))
-               return;
-
        kvm_unregister_irq_ack_notifier(&assigned_dev->ack_notifier);
+       assigned_dev->ack_notifier.gsi = -1;
 
        if (assigned_dev->irq_source_id != -1)
                kvm_free_irq_source_id(kvm, assigned_dev->irq_source_id);
        assigned_dev->irq_source_id = -1;
+       assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_GUEST_MASK);
+}
 
-       if (!assigned_dev->irq_requested_type)
-               return;
-
+/* The function implicit hold kvm->lock mutex due to cancel_work_sync() */
+static void deassign_host_irq(struct kvm *kvm,
+                             struct kvm_assigned_dev_kernel *assigned_dev)
+{
        /*
         * In kvm_free_device_irq, cancel_work_sync return true if:
         * 1. work is scheduled, and then cancelled.
@@ -184,17 +244,64 @@ static void kvm_free_assigned_irq(struct kvm *kvm,
         * now, the kvm state is still legal for probably we also have to wait
         * interrupt_work done.
         */
-       disable_irq_nosync(assigned_dev->host_irq);
-       cancel_work_sync(&assigned_dev->interrupt_work);
+       if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
+               int i;
+               for (i = 0; i < assigned_dev->entries_nr; i++)
+                       disable_irq_nosync(assigned_dev->
+                                          host_msix_entries[i].vector);
+
+               cancel_work_sync(&assigned_dev->interrupt_work);
+
+               for (i = 0; i < assigned_dev->entries_nr; i++)
+                       free_irq(assigned_dev->host_msix_entries[i].vector,
+                                (void *)assigned_dev);
+
+               assigned_dev->entries_nr = 0;
+               kfree(assigned_dev->host_msix_entries);
+               kfree(assigned_dev->guest_msix_entries);
+               pci_disable_msix(assigned_dev->dev);
+       } else {
+               /* Deal with MSI and INTx */
+               disable_irq_nosync(assigned_dev->host_irq);
+               cancel_work_sync(&assigned_dev->interrupt_work);
 
-       free_irq(assigned_dev->host_irq, (void *)assigned_dev);
+               free_irq(assigned_dev->host_irq, (void *)assigned_dev);
 
-       if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI)
-               pci_disable_msi(assigned_dev->dev);
+               if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSI)
+                       pci_disable_msi(assigned_dev->dev);
+       }
 
-       assigned_dev->irq_requested_type = 0;
+       assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_HOST_MASK);
 }
 
+static int kvm_deassign_irq(struct kvm *kvm,
+                           struct kvm_assigned_dev_kernel *assigned_dev,
+                           unsigned long irq_requested_type)
+{
+       unsigned long guest_irq_type, host_irq_type;
+
+       if (!irqchip_in_kernel(kvm))
+               return -EINVAL;
+       /* no irq assignment to deassign */
+       if (!assigned_dev->irq_requested_type)
+               return -ENXIO;
+
+       host_irq_type = irq_requested_type & KVM_DEV_IRQ_HOST_MASK;
+       guest_irq_type = irq_requested_type & KVM_DEV_IRQ_GUEST_MASK;
+
+       if (host_irq_type)
+               deassign_host_irq(kvm, assigned_dev);
+       if (guest_irq_type)
+               deassign_guest_irq(kvm, assigned_dev);
+
+       return 0;
+}
+
+static void kvm_free_assigned_irq(struct kvm *kvm,
+                                 struct kvm_assigned_dev_kernel *assigned_dev)
+{
+       kvm_deassign_irq(kvm, assigned_dev, assigned_dev->irq_requested_type);
+}
 
 static void kvm_free_assigned_device(struct kvm *kvm,
                                     struct kvm_assigned_dev_kernel
@@ -226,190 +333,244 @@ void kvm_free_all_assigned_devices(struct kvm *kvm)
        }
 }
 
-static int assigned_device_update_intx(struct kvm *kvm,
-                       struct kvm_assigned_dev_kernel *adev,
-                       struct kvm_assigned_irq *airq)
+static int assigned_device_enable_host_intx(struct kvm *kvm,
+                                           struct kvm_assigned_dev_kernel *dev)
 {
-       adev->guest_irq = airq->guest_irq;
-       adev->ack_notifier.gsi = airq->guest_irq;
+       dev->host_irq = dev->dev->irq;
+       /* Even though this is PCI, we don't want to use shared
+        * interrupts. Sharing host devices with guest-assigned devices
+        * on the same interrupt line is not a happy situation: there
+        * are going to be long delays in accepting, acking, etc.
+        */
+       if (request_irq(dev->host_irq, kvm_assigned_dev_intr,
+                       0, "kvm_assigned_intx_device", (void *)dev))
+               return -EIO;
+       return 0;
+}
 
-       if (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_INTX)
-               return 0;
+#ifdef __KVM_HAVE_MSI
+static int assigned_device_enable_host_msi(struct kvm *kvm,
+                                          struct kvm_assigned_dev_kernel *dev)
+{
+       int r;
 
-       if (irqchip_in_kernel(kvm)) {
-               if (!msi2intx &&
-                   (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI)) {
-                       free_irq(adev->host_irq, (void *)adev);
-                       pci_disable_msi(adev->dev);
-               }
+       if (!dev->dev->msi_enabled) {
+               r = pci_enable_msi(dev->dev);
+               if (r)
+                       return r;
+       }
 
-               if (!capable(CAP_SYS_RAWIO))
-                       return -EPERM;
+       dev->host_irq = dev->dev->irq;
+       if (request_irq(dev->host_irq, kvm_assigned_dev_intr, 0,
+                       "kvm_assigned_msi_device", (void *)dev)) {
+               pci_disable_msi(dev->dev);
+               return -EIO;
+       }
 
-               if (airq->host_irq)
-                       adev->host_irq = airq->host_irq;
-               else
-                       adev->host_irq = adev->dev->irq;
+       return 0;
+}
+#endif
 
-               /* Even though this is PCI, we don't want to use shared
-                * interrupts. Sharing host devices with guest-assigned devices
-                * on the same interrupt line is not a happy situation: there
-                * are going to be long delays in accepting, acking, etc.
-                */
-               if (request_irq(adev->host_irq, kvm_assigned_dev_intr,
-                               0, "kvm_assigned_intx_device", (void *)adev))
-                       return -EIO;
+#ifdef __KVM_HAVE_MSIX
+static int assigned_device_enable_host_msix(struct kvm *kvm,
+                                           struct kvm_assigned_dev_kernel *dev)
+{
+       int i, r = -EINVAL;
+
+       /* host_msix_entries and guest_msix_entries should have been
+        * initialized */
+       if (dev->entries_nr == 0)
+               return r;
+
+       r = pci_enable_msix(dev->dev, dev->host_msix_entries, dev->entries_nr);
+       if (r)
+               return r;
+
+       for (i = 0; i < dev->entries_nr; i++) {
+               r = request_irq(dev->host_msix_entries[i].vector,
+                               kvm_assigned_dev_intr, 0,
+                               "kvm_assigned_msix_device",
+                               (void *)dev);
+               /* FIXME: free requested_irq's on failure */
+               if (r)
+                       return r;
        }
 
-       adev->irq_requested_type = KVM_ASSIGNED_DEV_GUEST_INTX |
-                                  KVM_ASSIGNED_DEV_HOST_INTX;
        return 0;
 }
 
-#ifdef CONFIG_X86
-static int assigned_device_update_msi(struct kvm *kvm,
-                       struct kvm_assigned_dev_kernel *adev,
-                       struct kvm_assigned_irq *airq)
+#endif
+
+static int assigned_device_enable_guest_intx(struct kvm *kvm,
+                               struct kvm_assigned_dev_kernel *dev,
+                               struct kvm_assigned_irq *irq)
 {
-       int r;
+       dev->guest_irq = irq->guest_irq;
+       dev->ack_notifier.gsi = irq->guest_irq;
+       return 0;
+}
 
-       adev->guest_irq = airq->guest_irq;
-       if (airq->flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSI) {
-               /* x86 don't care upper address of guest msi message addr */
-               adev->irq_requested_type |= KVM_ASSIGNED_DEV_GUEST_MSI;
-               adev->irq_requested_type &= ~KVM_ASSIGNED_DEV_GUEST_INTX;
-               adev->ack_notifier.gsi = -1;
-       } else if (msi2intx) {
-               adev->irq_requested_type |= KVM_ASSIGNED_DEV_GUEST_INTX;
-               adev->irq_requested_type &= ~KVM_ASSIGNED_DEV_GUEST_MSI;
-               adev->ack_notifier.gsi = airq->guest_irq;
-       } else {
-               /*
-                * Guest require to disable device MSI, we disable MSI and
-                * re-enable INTx by default again. Notice it's only for
-                * non-msi2intx.
-                */
-               assigned_device_update_intx(kvm, adev, airq);
-               return 0;
+#ifdef __KVM_HAVE_MSI
+static int assigned_device_enable_guest_msi(struct kvm *kvm,
+                       struct kvm_assigned_dev_kernel *dev,
+                       struct kvm_assigned_irq *irq)
+{
+       dev->guest_irq = irq->guest_irq;
+       dev->ack_notifier.gsi = -1;
+       return 0;
+}
+#endif
+#ifdef __KVM_HAVE_MSIX
+static int assigned_device_enable_guest_msix(struct kvm *kvm,
+                       struct kvm_assigned_dev_kernel *dev,
+                       struct kvm_assigned_irq *irq)
+{
+       dev->guest_irq = irq->guest_irq;
+       dev->ack_notifier.gsi = -1;
+       return 0;
+}
+#endif
+
+static int assign_host_irq(struct kvm *kvm,
+                          struct kvm_assigned_dev_kernel *dev,
+                          __u32 host_irq_type)
+{
+       int r = -EEXIST;
+
+       if (dev->irq_requested_type & KVM_DEV_IRQ_HOST_MASK)
+               return r;
+
+       switch (host_irq_type) {
+       case KVM_DEV_IRQ_HOST_INTX:
+               r = assigned_device_enable_host_intx(kvm, dev);
+               break;
+#ifdef __KVM_HAVE_MSI
+       case KVM_DEV_IRQ_HOST_MSI:
+               r = assigned_device_enable_host_msi(kvm, dev);
+               break;
+#endif
+#ifdef __KVM_HAVE_MSIX
+       case KVM_DEV_IRQ_HOST_MSIX:
+               r = assigned_device_enable_host_msix(kvm, dev);
+               break;
+#endif
+       default:
+               r = -EINVAL;
        }
 
-       if (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI)
-               return 0;
+       if (!r)
+               dev->irq_requested_type |= host_irq_type;
 
-       if (irqchip_in_kernel(kvm)) {
-               if (!msi2intx) {
-                       if (adev->irq_requested_type &
-                                       KVM_ASSIGNED_DEV_HOST_INTX)
-                               free_irq(adev->host_irq, (void *)adev);
+       return r;
+}
 
-                       r = pci_enable_msi(adev->dev);
-                       if (r)
-                               return r;
-               }
+static int assign_guest_irq(struct kvm *kvm,
+                           struct kvm_assigned_dev_kernel *dev,
+                           struct kvm_assigned_irq *irq,
+                           unsigned long guest_irq_type)
+{
+       int id;
+       int r = -EEXIST;
+
+       if (dev->irq_requested_type & KVM_DEV_IRQ_GUEST_MASK)
+               return r;
 
-               adev->host_irq = adev->dev->irq;
-               if (request_irq(adev->host_irq, kvm_assigned_dev_intr, 0,
-                               "kvm_assigned_msi_device", (void *)adev))
-                       return -EIO;
+       id = kvm_request_irq_source_id(kvm);
+       if (id < 0)
+               return id;
+
+       dev->irq_source_id = id;
+
+       switch (guest_irq_type) {
+       case KVM_DEV_IRQ_GUEST_INTX:
+               r = assigned_device_enable_guest_intx(kvm, dev, irq);
+               break;
+#ifdef __KVM_HAVE_MSI
+       case KVM_DEV_IRQ_GUEST_MSI:
+               r = assigned_device_enable_guest_msi(kvm, dev, irq);
+               break;
+#endif
+#ifdef __KVM_HAVE_MSIX
+       case KVM_DEV_IRQ_GUEST_MSIX:
+               r = assigned_device_enable_guest_msix(kvm, dev, irq);
+               break;
+#endif
+       default:
+               r = -EINVAL;
        }
 
-       if (!msi2intx)
-               adev->irq_requested_type = KVM_ASSIGNED_DEV_GUEST_MSI;
+       if (!r) {
+               dev->irq_requested_type |= guest_irq_type;
+               kvm_register_irq_ack_notifier(kvm, &dev->ack_notifier);
+       } else
+               kvm_free_irq_source_id(kvm, dev->irq_source_id);
 
-       adev->irq_requested_type |= KVM_ASSIGNED_DEV_HOST_MSI;
-       return 0;
+       return r;
 }
-#endif
 
+/* TODO Deal with KVM_DEV_IRQ_ASSIGNED_MASK_MSIX */
 static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
-                                  struct kvm_assigned_irq
-                                  *assigned_irq)
+                                  struct kvm_assigned_irq *assigned_irq)
 {
-       int r = 0;
+       int r = -EINVAL;
        struct kvm_assigned_dev_kernel *match;
-       u32 current_flags = 0, changed_flags;
+       unsigned long host_irq_type, guest_irq_type;
 
-       mutex_lock(&kvm->lock);
+       if (!capable(CAP_SYS_RAWIO))
+               return -EPERM;
 
+       if (!irqchip_in_kernel(kvm))
+               return r;
+
+       mutex_lock(&kvm->lock);
+       r = -ENODEV;
        match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
                                      assigned_irq->assigned_dev_id);
-       if (!match) {
-               mutex_unlock(&kvm->lock);
-               return -EINVAL;
-       }
-
-       if (!match->irq_requested_type) {
-               INIT_WORK(&match->interrupt_work,
-                               kvm_assigned_dev_interrupt_work_handler);
-               if (irqchip_in_kernel(kvm)) {
-                       /* Register ack nofitier */
-                       match->ack_notifier.gsi = -1;
-                       match->ack_notifier.irq_acked =
-                                       kvm_assigned_dev_ack_irq;
-                       kvm_register_irq_ack_notifier(kvm,
-                                       &match->ack_notifier);
-
-                       /* Request IRQ source ID */
-                       r = kvm_request_irq_source_id(kvm);
-                       if (r < 0)
-                               goto out_release;
-                       else
-                               match->irq_source_id = r;
-
-#ifdef CONFIG_X86
-                       /* Determine host device irq type, we can know the
-                        * result from dev->msi_enabled */
-                       if (msi2intx)
-                               pci_enable_msi(match->dev);
-#endif
-               }
-       }
+       if (!match)
+               goto out;
 
-       if ((match->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) &&
-                (match->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_MSI))
-               current_flags |= KVM_DEV_IRQ_ASSIGN_ENABLE_MSI;
+       host_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_HOST_MASK);
+       guest_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_GUEST_MASK);
 
-       changed_flags = assigned_irq->flags ^ current_flags;
+       r = -EINVAL;
+       /* can only assign one type at a time */
+       if (hweight_long(host_irq_type) > 1)
+               goto out;
+       if (hweight_long(guest_irq_type) > 1)
+               goto out;
+       if (host_irq_type == 0 && guest_irq_type == 0)
+               goto out;
 
-       if ((changed_flags & KVM_DEV_IRQ_ASSIGN_MSI_ACTION) ||
-           (msi2intx && match->dev->msi_enabled)) {
-#ifdef CONFIG_X86
-               r = assigned_device_update_msi(kvm, match, assigned_irq);
-               if (r) {
-                       printk(KERN_WARNING "kvm: failed to enable "
-                                       "MSI device!\n");
-                       goto out_release;
-               }
-#else
-               r = -ENOTTY;
-#endif
-       } else if (assigned_irq->host_irq == 0 && match->dev->irq == 0) {
-               /* Host device IRQ 0 means don't support INTx */
-               if (!msi2intx) {
-                       printk(KERN_WARNING
-                              "kvm: wait device to enable MSI!\n");
-                       r = 0;
-               } else {
-                       printk(KERN_WARNING
-                              "kvm: failed to enable MSI device!\n");
-                       r = -ENOTTY;
-                       goto out_release;
-               }
-       } else {
-               /* Non-sharing INTx mode */
-               r = assigned_device_update_intx(kvm, match, assigned_irq);
-               if (r) {
-                       printk(KERN_WARNING "kvm: failed to enable "
-                                       "INTx device!\n");
-                       goto out_release;
-               }
-       }
+       r = 0;
+       if (host_irq_type)
+               r = assign_host_irq(kvm, match, host_irq_type);
+       if (r)
+               goto out;
 
+       if (guest_irq_type)
+               r = assign_guest_irq(kvm, match, assigned_irq, guest_irq_type);
+out:
        mutex_unlock(&kvm->lock);
        return r;
-out_release:
+}
+
+static int kvm_vm_ioctl_deassign_dev_irq(struct kvm *kvm,
+                                        struct kvm_assigned_irq
+                                        *assigned_irq)
+{
+       int r = -ENODEV;
+       struct kvm_assigned_dev_kernel *match;
+
+       mutex_lock(&kvm->lock);
+
+       match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+                                     assigned_irq->assigned_dev_id);
+       if (!match)
+               goto out;
+
+       r = kvm_deassign_irq(kvm, match, assigned_irq->flags);
+out:
        mutex_unlock(&kvm->lock);
-       kvm_free_assigned_device(kvm, match);
        return r;
 }
 
@@ -427,7 +588,7 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
                                      assigned_dev->assigned_dev_id);
        if (match) {
                /* device already assigned */
-               r = -EINVAL;
+               r = -EEXIST;
                goto out;
        }
 
@@ -464,8 +625,12 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
        match->host_devfn = assigned_dev->devfn;
        match->flags = assigned_dev->flags;
        match->dev = dev;
+       spin_lock_init(&match->assigned_dev_lock);
        match->irq_source_id = -1;
        match->kvm = kvm;
+       match->ack_notifier.irq_acked = kvm_assigned_dev_ack_irq;
+       INIT_WORK(&match->interrupt_work,
+                 kvm_assigned_dev_interrupt_work_handler);
 
        list_add(&match->list, &kvm->arch.assigned_dev_head);
 
@@ -878,6 +1043,8 @@ static void kvm_destroy_vm(struct kvm *kvm)
 #endif
 #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
        mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm);
+#else
+       kvm_arch_flush_shadow(kvm);
 #endif
        kvm_arch_destroy_vm(kvm);
        mmdrop(mm);
@@ -919,9 +1086,8 @@ int __kvm_set_memory_region(struct kvm *kvm,
 {
        int r;
        gfn_t base_gfn;
-       unsigned long npages;
-       int largepages;
-       unsigned long i;
+       unsigned long npages, ugfn;
+       unsigned long largepages, i;
        struct kvm_memory_slot *memslot;
        struct kvm_memory_slot old, new;
 
@@ -1010,6 +1176,14 @@ int __kvm_set_memory_region(struct kvm *kvm,
                        new.lpage_info[0].write_count = 1;
                if ((base_gfn+npages) % KVM_PAGES_PER_HPAGE)
                        new.lpage_info[largepages-1].write_count = 1;
+               ugfn = new.userspace_addr >> PAGE_SHIFT;
+               /*
+                * If the gfn and userspace address are not aligned wrt each
+                * other, disable large page support for this slot
+                */
+               if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE - 1))
+                       for (i = 0; i < largepages; ++i)
+                               new.lpage_info[i].write_count = 1;
        }
 
        /* Allocate page dirty bitmap if needed */
@@ -1043,8 +1217,10 @@ int __kvm_set_memory_region(struct kvm *kvm,
 
        kvm_free_physmem_slot(&old, npages ? &new : NULL);
        /* Slot deletion case: we have to update the current slot */
+       spin_lock(&kvm->mmu_lock);
        if (!npages)
                *memslot = old;
+       spin_unlock(&kvm->mmu_lock);
 #ifdef CONFIG_DMAR
        /* map the pages in iommu page table */
        r = kvm_iommu_map_pages(kvm, base_gfn, npages);
@@ -1454,12 +1630,14 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
        for (;;) {
                prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE);
 
-               if (kvm_cpu_has_interrupt(vcpu) ||
-                   kvm_cpu_has_pending_timer(vcpu) ||
-                   kvm_arch_vcpu_runnable(vcpu)) {
+               if ((kvm_arch_interrupt_allowed(vcpu) &&
+                                       kvm_cpu_has_interrupt(vcpu)) ||
+                               kvm_arch_vcpu_runnable(vcpu)) {
                        set_bit(KVM_REQ_UNHALT, &vcpu->requests);
                        break;
                }
+               if (kvm_cpu_has_pending_timer(vcpu))
+                       break;
                if (signal_pending(current))
                        break;
 
@@ -1593,6 +1771,88 @@ static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset)
        return 0;
 }
 
+#ifdef __KVM_HAVE_MSIX
+static int kvm_vm_ioctl_set_msix_nr(struct kvm *kvm,
+                                   struct kvm_assigned_msix_nr *entry_nr)
+{
+       int r = 0;
+       struct kvm_assigned_dev_kernel *adev;
+
+       mutex_lock(&kvm->lock);
+
+       adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+                                     entry_nr->assigned_dev_id);
+       if (!adev) {
+               r = -EINVAL;
+               goto msix_nr_out;
+       }
+
+       if (adev->entries_nr == 0) {
+               adev->entries_nr = entry_nr->entry_nr;
+               if (adev->entries_nr == 0 ||
+                   adev->entries_nr >= KVM_MAX_MSIX_PER_DEV) {
+                       r = -EINVAL;
+                       goto msix_nr_out;
+               }
+
+               adev->host_msix_entries = kzalloc(sizeof(struct msix_entry) *
+                                               entry_nr->entry_nr,
+                                               GFP_KERNEL);
+               if (!adev->host_msix_entries) {
+                       r = -ENOMEM;
+                       goto msix_nr_out;
+               }
+               adev->guest_msix_entries = kzalloc(
+                               sizeof(struct kvm_guest_msix_entry) *
+                               entry_nr->entry_nr, GFP_KERNEL);
+               if (!adev->guest_msix_entries) {
+                       kfree(adev->host_msix_entries);
+                       r = -ENOMEM;
+                       goto msix_nr_out;
+               }
+       } else /* Not allowed set MSI-X number twice */
+               r = -EINVAL;
+msix_nr_out:
+       mutex_unlock(&kvm->lock);
+       return r;
+}
+
+static int kvm_vm_ioctl_set_msix_entry(struct kvm *kvm,
+                                      struct kvm_assigned_msix_entry *entry)
+{
+       int r = 0, i;
+       struct kvm_assigned_dev_kernel *adev;
+
+       mutex_lock(&kvm->lock);
+
+       adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+                                     entry->assigned_dev_id);
+
+       if (!adev) {
+               r = -EINVAL;
+               goto msix_entry_out;
+       }
+
+       for (i = 0; i < adev->entries_nr; i++)
+               if (adev->guest_msix_entries[i].vector == 0 ||
+                   adev->guest_msix_entries[i].entry == entry->entry) {
+                       adev->guest_msix_entries[i].entry = entry->entry;
+                       adev->guest_msix_entries[i].vector = entry->gsi;
+                       adev->host_msix_entries[i].entry = entry->entry;
+                       break;
+               }
+       if (i == adev->entries_nr) {
+               r = -ENOSPC;
+               goto msix_entry_out;
+       }
+
+msix_entry_out:
+       mutex_unlock(&kvm->lock);
+
+       return r;
+}
+#endif
+
 static long kvm_vcpu_ioctl(struct file *filp,
                           unsigned int ioctl, unsigned long arg)
 {
@@ -1864,6 +2124,11 @@ static long kvm_vm_ioctl(struct file *filp,
                break;
        }
        case KVM_ASSIGN_IRQ: {
+               r = -EOPNOTSUPP;
+               break;
+       }
+#ifdef KVM_CAP_ASSIGN_DEV_IRQ
+       case KVM_ASSIGN_DEV_IRQ: {
                struct kvm_assigned_irq assigned_irq;
 
                r = -EFAULT;
@@ -1874,6 +2139,18 @@ static long kvm_vm_ioctl(struct file *filp,
                        goto out;
                break;
        }
+       case KVM_DEASSIGN_DEV_IRQ: {
+               struct kvm_assigned_irq assigned_irq;
+
+               r = -EFAULT;
+               if (copy_from_user(&assigned_irq, argp, sizeof assigned_irq))
+                       goto out;
+               r = kvm_vm_ioctl_deassign_dev_irq(kvm, &assigned_irq);
+               if (r)
+                       goto out;
+               break;
+       }
+#endif
 #endif
 #ifdef KVM_CAP_DEVICE_DEASSIGNMENT
        case KVM_DEASSIGN_PCI_DEVICE: {
@@ -1917,7 +2194,29 @@ static long kvm_vm_ioctl(struct file *filp,
                vfree(entries);
                break;
        }
+#ifdef __KVM_HAVE_MSIX
+       case KVM_ASSIGN_SET_MSIX_NR: {
+               struct kvm_assigned_msix_nr entry_nr;
+               r = -EFAULT;
+               if (copy_from_user(&entry_nr, argp, sizeof entry_nr))
+                       goto out;
+               r = kvm_vm_ioctl_set_msix_nr(kvm, &entry_nr);
+               if (r)
+                       goto out;
+               break;
+       }
+       case KVM_ASSIGN_SET_MSIX_ENTRY: {
+               struct kvm_assigned_msix_entry entry;
+               r = -EFAULT;
+               if (copy_from_user(&entry, argp, sizeof entry))
+                       goto out;
+               r = kvm_vm_ioctl_set_msix_entry(kvm, &entry);
+               if (r)
+                       goto out;
+               break;
+       }
 #endif
+#endif /* KVM_CAP_IRQ_ROUTING */
        default:
                r = kvm_arch_vm_ioctl(filp, ioctl, arg);
        }
@@ -2112,15 +2411,15 @@ EXPORT_SYMBOL_GPL(kvm_handle_fault_on_reboot);
 static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
                      void *v)
 {
-       if (val == SYS_RESTART) {
-               /*
-                * Some (well, at least mine) BIOSes hang on reboot if
-                * in vmx root mode.
-                */
-               printk(KERN_INFO "kvm: exiting hardware virtualization\n");
-               kvm_rebooting = true;
-               on_each_cpu(hardware_disable, NULL, 1);
-       }
+       /*
+        * Some (well, at least mine) BIOSes hang on reboot if
+        * in vmx root mode.
+        *
+        * And Intel TXT required VMX off for all cpu when system shutdown.
+        */
+       printk(KERN_INFO "kvm: exiting hardware virtualization\n");
+       kvm_rebooting = true;
+       on_each_cpu(hardware_disable, NULL, 1);
        return NOTIFY_OK;
 }
 
@@ -2354,9 +2653,6 @@ int kvm_init(void *opaque, unsigned int vcpu_size,
 
        kvm_preempt_ops.sched_in = kvm_sched_in;
        kvm_preempt_ops.sched_out = kvm_sched_out;
-#ifndef CONFIG_X86
-       msi2intx = 0;
-#endif
 
        return 0;